Вопрос

I have a simple REST api which sends data in JSON such as this:

http://myapp/color (POST w/ data in JSON) - Creates a new color in DB
http://myapp/color/id (GET) - Fetches details for a color from DB
http://myapp/color (GET) - Fetches details for all colors in DB

I would like to create a SOAP API for these three functions as well. So I'm going with Spring-WS.

I've created the SOAP API for the creation. With the following XSD

<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:hr="http://www.myveryimportantcompany.com/tr/schemas"
           targetNamespace="http://www.myveryimportantcompany.com/tr/schemas"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">
<xs:element name="ColorRequest">
    <xs:complexType>
        <xs:all>
            <xs:element name="Color" type="hr:ColorType"/>
        </xs:all>
    </xs:complexType>
</xs:element>
<xs:complexType name="ColorType">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
<xs:element name="ColorResponse">
    <xs:complexType>
        <xs:sequence>
            <xs:element name="status" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:element>
</xs:schema>

I've also written functional test for the above which works fine.

Questions - I've never created a SOAP WS in the past so please ignore if questions are stupid.

  • How would the XSD look like for the remaining two functions?
  • Do I need a separate XSD for each function?
  • Can I test the SOAP service with a GUI as well? I gave SOAP GUI a show but it needs a WSDL. How can I create that?

PS: I'm using Spring-WS plugin from grails.

Это было полезно?

Решение

This is a kind of a subjective question I bet. I will try to answer as much elaborated as I can to make it useful. Bear with me. :)

First Thing First:-

  • SpringWS plugin uses contract-first webservice. The schema which you have created here should be a contract for the underlying webservice.
  • Each of the webservice should have its own contract which means its own schema.
  • SpringWS follows a convention of creating an Endpoint with the name same as the name of the contract schema.
  • You can use inheritance in the endpoints which will help you create a single xsd schema for all the contracts. In that case you have to inherit the parent endpoint in the corresponding child endpoints.

Example:-
For everyone's convenience lets use a User service instead of Color.

//Domain:-
class User{
    String name
    String email
    Integer age
}

I would prepare a base schema for this entity, some what similar to what you did earlier for Color:

<!-- User.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:hr="http://www.myveryimportantcompany.com/tr/schemas"
           targetNamespace="http://www.myveryimportantcompany.com/tr/schemas"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">
<xs:complexType name="UserType">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
        <xs:element name="email" type="xs:string"/>
        <xs:element name="age" type="xs:integer"/>
    </xs:sequence>
</xs:complexType>

<xs:element name="User" type="hr:UserType"/>

</xs:schema>

Now come to each contract for each Service:-

<!-- GetUserService.xsd -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           xmlns:hr="http://www.myveryimportantcompany.com/tr/schemas"
           targetNamespace="http://www.myveryimportantcompany.com/tr/schemas"
           elementFormDefault="qualified"
           attributeFormDefault="unqualified">
<xs:element name="GetUserRequest" type="hr:GetUserRequestType"/>
<xs:complexType name="GetUserRequestType">
    <xs:sequence>
        <xs:element name="name" type="xs:string"/>
    </xs:sequence>
</xs:complexType>

<xs:element name="GetUserResponse" type="hr:GetUserResponseType"/>    
<xs:complexType name="GetUserRequestType">
    <xs:sequence>
        <xs:element ref="hr:User"/>
    </xs:sequence>
</xs:complexType>
</xs:schema>

Similarly you can have UpdateUserService.xsd doing the update [POST, PUT] piece.

Alternatively, you can accumulate all the xsds to a single contract named UserServices.xsd

Caveat
In case you have only one xsd for all service then you have to create a parent endpoint named (exactly same) as UserServicesEndpoint.groovy (see springws docs how to create endpoints), then your services endpoint would belike

class GetUserServiceEndpoint extends UserServicesEndpoint{....}
class UpdateUserServiceEndpoint extends UserServicesEndpoint{....}

In case you have all xsds separate, you do not need the inheritance.

Answers to Questions:

  1. How would the XSD look like for the remaining two functions?
    By now you know how should it look. The names should be something like UpdateColorService.xsd, GetColorService.xsd, GetAllColorsService.xsd

  2. Do I need a separate XSD for each function?
    Follow above. You can have separate or you can have them in one parent xsd. In that case, there has to be a parent endpoint as well.

  3. Can I test the SOAP service with a GUI as well? I gave SOAP GUI a show but it needs a WSDL. How can I create that?
    Yes you can. The best tool I found is SoapUI (free version is sufficient for me). You can also use Apache JMeter, if you are comfortable with it. Contract-first services always need a WSDL to run. As part of SpringWS plugin, you have a splendid DSL support which creates a WSDL for you after you run the application. Follow the docs again. I can explain that in a different question, because this answer has become an epic by now.

Words of Advice:

  • Finally, why do you need a SOAP Service when the whole world is RESTing in peace? :)

  • springws plugin is almost obsolete and has not been supported for years. I have customized the plugin to my need and have not submitted it to Grails PLugins yet. Did not feel like? But I think I have to now, since @Anthony is using it. :)

  • The plugin has jars inside project's lib directory which may clash with your dependencies.

  • Plugin uses old version of spring-ws-core which is definitely going to crash with spring-core:3.1.2 which comes with Grails 2.2.x.

  • You might get compilation errors with newer version of JDK (7 or above).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top