Compare commits

..

3 Commits

Author SHA1 Message Date
Runar Ingebrigtsen 60d4332ef2 bump version
CI / test (3.1) (push) Successful in 13s
CI / test (3.2) (push) Successful in 13s
CI / test (3.3) (push) Successful in 13s
2026-06-23 14:53:18 +02:00
Runar Ingebrigtsen edc0b2945b tolerate empty string result from Fiken API
CI / test (3.1) (push) Successful in 35s
CI / test (3.2) (push) Successful in 33s
CI / test (3.3) (push) Successful in 33s
2026-06-23 14:52:51 +02:00
Runar Ingebrigtsen 5f2074ee25 describe usage 2026-06-23 14:52:08 +02:00
4 changed files with 50 additions and 2 deletions
+43
View File
@@ -8,6 +8,18 @@ the Norwegian accounting and invoicing platform.
- Automatic pagination with `auto_paging_each` - Automatic pagination with `auto_paging_each`
- HTTP errors mapped to typed exceptions, with retry on rate limits (429) and server errors - HTTP errors mapped to typed exceptions, with retry on rate limits (429) and server errors
> **API reference.** This gem is a thin transport over the Fiken API — it does not
> redefine the data model. Request bodies and response fields use exactly the names,
> types and nesting from the official OpenAPI (Swagger) specification. Keep it open
> while you build:
>
> - Interactive docs: <https://api.fiken.no/api/v2/docs>
> - OpenAPI spec (YAML): <https://api.fiken.no/api/v2/docs/swagger.yaml>
>
> Each resource below maps to a tag in that spec, and every `Fiken::Object` you get
> back mirrors the corresponding response schema. See
> [Response objects & data structures](#response-objects--data-structures).
## Installation ## Installation
```ruby ```ruby
@@ -135,6 +147,37 @@ client.invoices(slug).attachments(456).add(io: pdf_io, filename: "invoice.pdf",
client.inbox(slug).create(path: "receipt.pdf", name: "Office supplies") client.inbox(slug).create(path: "receipt.pdf", name: "Office supplies")
``` ```
## Response objects & data structures
Responses are wrapped in `Fiken::Object`, a lightweight, read-only struct built
recursively from the JSON. The gem deliberately does **not** impose its own typed
models — the shape of every object is defined by the Fiken OpenAPI spec, so that is
your source of truth for field names and types:
- OpenAPI spec (YAML): <https://api.fiken.no/api/v2/docs/swagger.yaml>
- Interactive docs: <https://api.fiken.no/api/v2/docs>
For example, an invoice returned by `client.invoices(slug).find(id)` mirrors the
spec's `invoiceResult` schema, so the keys documented there are exactly what you
access:
```ruby
invoice = client.invoices(slug).find(456)
invoice.invoiceNumber # camelCase — exactly as in the spec
invoice.invoice_number # snake_case alias for the same field
invoice[:invoiceNumber] # hash-style access
invoice.lines.first.vatType # nested objects/arrays wrapped recursively
invoice.to_h # plain Hash with the original (camelCase) keys
invoice.keys # inspect available fields at runtime
```
Because access maps straight onto the spec schema, the schema name to look up for a
given call is predictable: `*Result` schemas for responses (e.g. `invoiceResult`,
`saleResult`, `contact`) and `*Request` schemas for the hashes you pass to
`create`/`update` (e.g. `invoiceRequest`, `fullCreditNoteRequest`). When in doubt,
`obj.to_h` shows you the raw structure as Fiken returned it.
## Error handling ## Error handling
Non-success responses raise a typed subclass of `Fiken::Error`, each carrying Non-success responses raise a typed subclass of `Fiken::Error`, each carrying
+2 -1
View File
@@ -12,7 +12,8 @@ module Fiken
class Object class Object
def initialize(attributes = {}) def initialize(attributes = {})
@attributes = {} @attributes = {}
(attributes || {}).each { |key, value| @attributes[key.to_sym] = wrap(value) } attributes = {} unless attributes.is_a?(Hash)
attributes.each { |key, value| @attributes[key.to_sym] = wrap(value) }
end end
def [](key) def [](key)
+1 -1
View File
@@ -1,5 +1,5 @@
# frozen_string_literal: true # frozen_string_literal: true
module Fiken module Fiken
VERSION = "0.1.0" VERSION = "0.1.1"
end end
+4
View File
@@ -46,4 +46,8 @@ RSpec.describe Fiken::Object do
expect(object.key?(:invoiceNumber)).to be(true) expect(object.key?(:invoiceNumber)).to be(true)
expect(object.key?(:missing)).to be(false) expect(object.key?(:missing)).to be(false)
end end
it "treats a non-Hash body (e.g. empty string from a 204 response) as empty" do
expect(described_class.new("").keys).to eq([])
end
end end