inossidabile / wash_out

Dead simple Rails 4/5 SOAP server library
Other
342 stars 241 forks source link

Define types outside of an action and reuse then in actions #21

Closed Bjorn-Nilsson closed 12 years ago

Bjorn-Nilsson commented 12 years ago

When you generate a WSDL and use the same type many times it would be nice if you could define some types at the top of the WSDL and then just refer to them. It would be very nice if it was possible to have something like soap_action in the controller but named soap_types where you could define some types like this:

soap_types { :Address => { :City => :string, :Street => :string },

Person => { :first_name => string, :last_name => :string, :address => :Address } }

and then:

soap_action "make_sale", :args => :Order => { :Buyer => :Person, :Seller => :Person }, :return => :string

I tried thinking about how to do this but couldn't quite figure it out. What do you guys think?

inossidabile commented 12 years ago

There are two possible options to solve this. Both are actually available. You can assign your hash parts to variables.

person = {:title => :string, :sex => :boolean}
school = {:number => :integer, :persons => [person]}

The second option is to use the internal representation of WashOut::Param. I'm not quite sure is this approach should even be considered as well. Doesn't first option solve this problem quite clear?

inossidabile commented 12 years ago

I mean you can use not only variables actually. Those can be constants or external module attributes. You are free to structure your code with any available option since all you need is just to create large hash. I trust we should not overengineer this task.

Bjorn-Nilsson commented 12 years ago

I do agree with you, the request is from someone I build the service for. They are using .NET and want to have the wsdl in specific ways.

The problem isn't so much in the ruby code, your example solves that nicely, but in the generated wsdl. Lets say i want to have a complex type "Price" that contains amount and currency. Then I want to use Price in several places: delivery_price, insurance_price, total_price, item_price, installation_price, etc. etc

This will mean I get a new definition for each of these types instead of one definition of Price.

I understand if you think this is an edge case and that it makes the code too complex.

Thanks for your insanely quick responses btw!

Bjorn-Nilsson commented 12 years ago

If we had this opportynity to define our own types, people who want to do crazy stuff like enumerations could maybe do it that way too. Just a possibility to insert a block of xml could probably help some people who are forced to do strange things. (the more I learn about SOAP, the less I like it.)

inossidabile commented 12 years ago

Ah. I see. We could check the entity fields' set to avoid duplications. And thus at WSDL would take the name of this entity from the first definition. However it doesn't feel very right to me.

I'll try to experiment with WashOut::Param a bit then to make it lightweight so you could use it directly.

Bjorn-Nilsson commented 12 years ago

That sounds great! It's fine if I have do do a bit of manual stuff as long as it is possible. Thanks again!

spockz commented 12 years ago

I'm also in favor for this. It makes the service a lot easier to use in strongly typed languages.

inossidabile commented 12 years ago

CC: @spockz , @Bjorn-Nilsson, @rngtng

Guys, I wonder if you have ideas for a well interface for this. I didn't succeed with a tiny brainstorm I had on this weekend :(

spockz commented 12 years ago

I would suggest something like the following

soap_type :name {...} (types as normal

you could then use the type inside a soap_action (or a soap_type) with the following function: typeref. This function could wrap the name (a String) in some constructor. The WSDL generator and the request parser/response generator need to know about this constructor to alter their parsing and output accordingly.

I'm not sure how easy this is to implement, I haven't tried it yet.

inossidabile commented 12 years ago

Right. But where exactly should you define this? It would make sense to allow sharing types among controllers.

spockz commented 12 years ago

I believe that you could achieve that with either class inheritance (if it is really something global) or just mix it in.

inossidabile commented 12 years ago

Inheritance is not a good solution for the controllers. However mixins sound pretty good. For some reason I didn't think about it. Thank you, this is good possible solution.