postal_codes_client 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: afd74ae3b8c6bcd3daf44f1b77ef6744fcfde28c52ca1ce29ee51dd2bba8b017
4
+ data.tar.gz: 341b3d9bd9731b211dd1e303ced461d9a1e4cd0a41508f657b54cf75e2825d1e
5
+ SHA512:
6
+ metadata.gz: 97b7403b75759f1e96cfb50294cb3037e1469c04b50b5f5008811440d16b6624a1bb36a3695a1ad32c121cb1b997f879a08dddcd128bcb73bf6b24709ef3c771
7
+ data.tar.gz: cd34f45d135c586061e238412017d55aa7045ddfc708ff56a5493c9e72aff84cc8db1ec895a9caac96e164cbf03970fc1e3b9b6a8ac813e0cb8265d33d000018
data/README.md ADDED
@@ -0,0 +1,83 @@
1
+ # PostalCodesClient
2
+
3
+ Ruby-Client-Gem für die PLZ API – Postleitzahlen-Suche über 100+ Länder.
4
+
5
+ ## Installation
6
+
7
+ ```ruby
8
+ # Gemfile
9
+ gem "postal_codes_client", path: "../postal_codes_client"
10
+ ```
11
+
12
+ Oder als lokales Gem:
13
+
14
+ ```bash
15
+ cd postal_codes_client
16
+ gem build postal_codes_client.gemspec
17
+ gem install postal_codes_client-0.1.0.gem
18
+ ```
19
+
20
+ ## Konfiguration
21
+
22
+ ```ruby
23
+ require "postal_codes_client"
24
+
25
+ PostalCodesClient.configure do |config|
26
+ config.base_url = "http://localhost:3000" # Standard
27
+ config.api_token = "dein_api_token"
28
+ config.timeout = 30 # Sekunden (Standard)
29
+ end
30
+ ```
31
+
32
+ ## Verwendung
33
+
34
+ ### Client erstellen
35
+
36
+ ```ruby
37
+ # Globale Konfiguration nutzen
38
+ client = PostalCodesClient::Client.new
39
+
40
+ # Oder Token direkt übergeben
41
+ client = PostalCodesClient::Client.new(
42
+ api_token: "dein_api_token",
43
+ base_url: "https://api.example.com"
44
+ )
45
+ ```
46
+
47
+ ```ruby
48
+ # PLZ-Suche (Teilsuche möglich)
49
+ results = client.postal_codes.search(q: "803", country: "DE")
50
+ results[:results].each do |pc|
51
+ puts "#{pc[:zipcode]} #{pc[:place]} (#{pc[:state]})"
52
+ end
53
+
54
+ # Suche ohne Länderfilter
55
+ results = client.postal_codes.search(q: "1010", limit: 10)
56
+
57
+ # Verfügbare Länder auflisten
58
+ countries = client.postal_codes.countries
59
+ puts countries[:countries].join(", ")
60
+ ```
61
+
62
+ ### Fehlerbehandlung
63
+
64
+ ```ruby
65
+ begin
66
+ client.postal_codes.search(q: "803")
67
+ rescue PostalCodesClient::AuthenticationError => e
68
+ puts "Nicht autorisiert: #{e.message}"
69
+ rescue PostalCodesClient::ValidationError => e
70
+ puts "Validierungsfehler: #{e.errors.join(', ')}"
71
+ rescue PostalCodesClient::ApiError => e
72
+ puts "API-Fehler (#{e.status}): #{e.message}"
73
+ rescue PostalCodesClient::Error => e
74
+ puts "Fehler: #{e.message}"
75
+ end
76
+ ```
77
+
78
+ ## API-Referenz
79
+
80
+ | Methode | Beschreibung |
81
+ |---------|-------------|
82
+ | `client.postal_codes.search(q:, country:, limit:)` | PLZ-Suche |
83
+ | `client.postal_codes.countries` | Verfügbare Länder |
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "net/http"
4
+ require "uri"
5
+ require "json"
6
+
7
+ module PostalCodesClient
8
+ class Client
9
+ attr_reader :auth, :postal_codes
10
+
11
+ def initialize(api_token: nil, base_url: nil)
12
+ @api_token = api_token || PostalCodesClient.configuration.api_token
13
+ @base_url = base_url || PostalCodesClient.configuration.base_url
14
+ @timeout = PostalCodesClient.configuration.timeout
15
+
16
+ @auth = Resources::Auth.new(self)
17
+ @postal_codes = Resources::PostalCodes.new(self)
18
+ end
19
+
20
+ # Update the API token (e.g. after login or token regeneration).
21
+ def api_token=(token)
22
+ @api_token = token
23
+ end
24
+
25
+ # Perform a GET request.
26
+ def get(path, params = {})
27
+ uri = build_uri(path, params)
28
+ request = Net::HTTP::Get.new(uri)
29
+ execute(uri, request)
30
+ end
31
+
32
+ # Perform a POST request with a JSON body.
33
+ def post(path, body = nil)
34
+ uri = build_uri(path)
35
+ request = Net::HTTP::Post.new(uri)
36
+ if body
37
+ request.body = JSON.generate(body)
38
+ request["Content-Type"] = "application/json"
39
+ end
40
+ execute(uri, request)
41
+ end
42
+
43
+ private
44
+
45
+ def build_uri(path, params = {})
46
+ uri = URI.join(@base_url, path)
47
+ uri.query = URI.encode_www_form(params) unless params.empty?
48
+ uri
49
+ end
50
+
51
+ def execute(uri, request)
52
+ request["Authorization"] = "Bearer #{@api_token}" if @api_token
53
+ request["Accept"] = "application/json"
54
+
55
+ http = Net::HTTP.new(uri.host, uri.port)
56
+ http.use_ssl = uri.scheme == "https"
57
+ http.open_timeout = @timeout
58
+ http.read_timeout = @timeout
59
+
60
+ response = http.request(request)
61
+ handle_response(response)
62
+ end
63
+
64
+ def handle_response(response)
65
+ body = response.body ? JSON.parse(response.body, symbolize_names: true) : nil
66
+
67
+ case response.code.to_i
68
+ when 200, 201
69
+ body
70
+ when 401
71
+ raise AuthenticationError, body&.dig(:error) || "Unauthorized"
72
+ when 422
73
+ raise ValidationError.new(
74
+ body&.dig(:error) || "Validation failed",
75
+ errors: body&.dig(:errors) || []
76
+ )
77
+ else
78
+ raise ApiError.new(
79
+ body&.dig(:error) || "API error (HTTP #{response.code})",
80
+ status: response.code.to_i,
81
+ body: body
82
+ )
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PostalCodesClient
4
+ class Configuration
5
+ attr_accessor :base_url, :api_token, :timeout
6
+
7
+ def initialize
8
+ @base_url = "http://localhost:3000"
9
+ @api_token = nil
10
+ @timeout = 30
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PostalCodesClient
4
+ class Error < StandardError; end
5
+
6
+ class AuthenticationError < Error; end
7
+
8
+ class ValidationError < Error
9
+ attr_reader :errors
10
+
11
+ def initialize(message, errors: [])
12
+ @errors = errors
13
+ super(message)
14
+ end
15
+ end
16
+
17
+ class ApiError < Error
18
+ attr_reader :status, :body
19
+
20
+ def initialize(message, status:, body: nil)
21
+ @status = status
22
+ @body = body
23
+ super(message)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PostalCodesClient
4
+ module Resources
5
+ class PostalCodes
6
+ def initialize(client)
7
+ @client = client
8
+ end
9
+
10
+ # Search for postal codes.
11
+ #
12
+ # @param q [String] Full or partial postal code (required)
13
+ # @param country [String, nil] ISO country code, e.g. "DE", "AT", "CH"
14
+ # @param limit [Integer, nil] Max results (default 50, max 200)
15
+ # @return [Hash] { query:, country:, count:, results: [...] }
16
+ def search(q:, country: nil, limit: nil)
17
+ params = { q: q }
18
+ params[:country] = country if country
19
+ params[:limit] = limit if limit
20
+ @client.get("/api/v1/postal_codes", params)
21
+ end
22
+
23
+ # List all available country codes.
24
+ #
25
+ # @return [Hash] { countries: ["AT", "CH", "DE", ...] }
26
+ def countries
27
+ @client.get("/api/v1/postal_codes/countries")
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PostalCodesClient
4
+ VERSION = "0.1.0"
5
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "postal_codes_client/version"
4
+ require_relative "postal_codes_client/configuration"
5
+ require_relative "postal_codes_client/errors"
6
+ require_relative "postal_codes_client/resources/auth"
7
+ require_relative "postal_codes_client/resources/postal_codes"
8
+ require_relative "postal_codes_client/client"
9
+
10
+ module PostalCodesClient
11
+ class << self
12
+ attr_writer :configuration
13
+
14
+ def configuration
15
+ @configuration ||= Configuration.new
16
+ end
17
+
18
+ def configure
19
+ yield(configuration)
20
+ end
21
+
22
+ def reset!
23
+ @configuration = Configuration.new
24
+ end
25
+ end
26
+ end
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: postal_codes_client
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - PLZ API
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-04-08 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '2.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ description: A Ruby gem to search postal codes across 100+ countries via the PLZ API.
70
+ Supports authentication, postal code search, and country listing.
71
+ email:
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - README.md
77
+ - lib/postal_codes_client.rb
78
+ - lib/postal_codes_client/client.rb
79
+ - lib/postal_codes_client/configuration.rb
80
+ - lib/postal_codes_client/errors.rb
81
+ - lib/postal_codes_client/resources/postal_codes.rb
82
+ - lib/postal_codes_client/version.rb
83
+ homepage: https://github.com/postal-codes-rails
84
+ licenses:
85
+ - MIT
86
+ metadata: {}
87
+ post_install_message:
88
+ rdoc_options: []
89
+ require_paths:
90
+ - lib
91
+ required_ruby_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '3.1'
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: '0'
101
+ requirements: []
102
+ rubygems_version: 3.4.20
103
+ signing_key:
104
+ specification_version: 4
105
+ summary: Ruby client for the PLZ (Postleitzahlen) API
106
+ test_files: []