Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add register stations #18

Merged
merged 22 commits into from
Jun 1, 2020
Merged

Conversation

wasabigeek
Copy link
Collaborator

@wasabigeek wasabigeek commented May 30, 2020

Start support for stations (#10) by adding a register_station method to Client (https://openweathermap.org/stations#create_station).

Opening for early feedback, some questions:

  • should all the endpoints go into the client, or should the more RESTful resources be a separate component?
  • stations seem to require a minimum API version of 3, I could add some checks on the version URL when attempting to use the stations endpoints, what do you think?
  • registering stations requires JSON requests, I hacked something around for now as the library only allows form requests, wondering if you had advice on the best way to approach this?

@dblock
Copy link
Owner

dblock commented May 30, 2020

Start support for stations by adding a register_stations method to Client (https://openweathermap.org/stations#create_station).

Cool. Thanks!

  • should all the endpoints go into the client, or should the more RESTful resources be a separate component?

To be consistent I think the client should have register_station, get_station, update_station, etc., but I would also add methods to the Station model, e.g. register!, update! or destroy! that call those, e.g. client.register_station(self.to_h) or something like that.

  • stations seem to require a minimum API version of 3, I could add some checks on the version URL when attempting to use the stations endpoints, what do you think?

Maybe, I wouldn't care enough. I would just call out that this library also now supports some 3.0 beta functions. If you use 2.5 endpoints for station it's going to give you an error anyway (write a test).

  • registering stations requires JSON requests, I hacked something around for now as the library only allows form requests, wondering if you had advice on the best way to approach this?

This doesn't seem right. The OpenWeatherMap docs say that if you pass Content-Type: application/json in the HTTP request you'll get back JSON. Either way adding endpoint-specific parameters belongs in the endpoint method, not in the middleware.

This seems unnecessary. I think 2.5 API never uses POST, so you can just default it to application/json. I could be wrong, in which case I would pass a content_type option instead of use_json, but that's a small implementation detail.

Copy link
Owner

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The OO interface is not quite an OO interface, but almost there!

@@ -10,7 +10,8 @@ class Model < Hashie::Trash
attr_reader :options

def initialize(args = nil, options = {})
super args
transformed_args = args.respond_to?(:transform_keys) ? args.transform_keys(&:to_s) : args
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Care to explain?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A symbol-keyed hash was “ignored” by the model, I think because a Hashie::Dash property will account for whether it’s defined as a string or symbol (though there didn’t seem to be an issue retrieving the property via a method)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's possible that the model class needs a merge initializer instead. Either way make sure to have a spec for this and we can fix it later.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Finding this hard to test on Model itself, would it be sufficient to test Station for now?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes.

property 'updated_at' # timestamp when station was updated
property 'rank' # rank of station

def self.register!(attributes)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This becomes a method that can take additional options:

def register!(options = {})
   OpenWeather::Client.new.register_station(attributes, options)
end


require 'spec_helper'

RSpec.describe OpenWeather::Models::Station do
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably shorter to use the same VCR here. The problem with the double is that it will continue working even if we break the API call.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, since that client method is unit-tested already, wouldn't it be sufficient to unit-test this as well (check that we call client with the right params)?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's sufficient, but implies behavior and IMHO hides bugs. I've debugged my fair share of double's to avoid them, more often than to use them. That said no strong opinions.

include_context 'API client'

it 'registers a station', vcr: { cassette_name: 'stations/register_success' } do
client.endpoint = 'https://api.openweathermap.org/data/3.0'
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's extend the context to take options like so:

include_context 'API client', endpoint: 'https://api.openweathermap.org/data/3.0'

Copy link
Collaborator Author

@wasabigeek wasabigeek Jun 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

altitude: 150
)
expect(data).to be_a(OpenWeather::Models::Station)
expect(data).to have_attributes(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As long as have_attributes starts failing if I add an extra attribute, this works, but it is inconsistent with other tests. Not sure if I care about the latter much, just thinking out loud.

Copy link
Collaborator Author

@wasabigeek wasabigeek Jun 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does fail, but perhaps with a more cryptic error:

  1) stations registers a station
     Failure/Error:
       expect(data).to have_attributes(
         ...
         wazzoo: 'test'
       )

       expected {...} to respond to :wazzoo with 0 arguments

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's better, it lets us check all attributes. I wouldn't mind if all the other tests changed ;)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So that's better, it lets us check all attributes. I wouldn't mind if all the other tests changed ;)

Can I open a separate PR for that 🤣

Copy link
Owner

@dblock dblock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's see the model change and I'm happy with this.

module OpenWeather
module Models
class Station < Model
# internal identifier for the station
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be consistent, put the comment after the code line.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My bad, I was trying to see if it could work with both 'id' and 'ID' and thought the line was too long

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can probably alias it if you really want to.

before do
OpenWeather::Config.reset
OpenWeather::Config.endpoint = params[:endpoint] if params&.key?(:endpoint)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a future PR, I'd like to make it future proof able to write OpenWeather::Client.configure(params) here.

property 'rank' # rank of station

def register!
data = OpenWeather::Client.new.register_station(to_h)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For future update, we can save the extra instance construction with OpenWeather::Client.new.post('stations', options). I think that's OK to duplicate.

@dblock dblock merged commit 79ee36f into dblock:master Jun 1, 2020
@dblock
Copy link
Owner

dblock commented Jun 1, 2020

Good stuff, merged.

Want to add the rest of station methods?

@wasabigeek wasabigeek deleted the add-register-stations branch June 1, 2020 14:34
@wasabigeek
Copy link
Collaborator Author

Want to add the rest of station methods?

Will slowly chip at them!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants