├── .gitignore ├── Procfile ├── README.md ├── app.py ├── requirements.txt ├── static ├── SoapApi.js └── normalize.css └── templates ├── 403.html ├── 404.html ├── 410.html ├── 500.html └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | venv 3 | *.pyc 4 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python app.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # flask-soap-server 2 | 3 | A simple example of how to use SOAP with Flask. 4 | 5 | With this project you have a base soap server written in python with a javascript client. 6 | 7 | ## Dependencies 8 | 9 | All dependencies are written in requirements.txt and you can install them with: 10 | 11 | ```bash 12 | pip install -r requirements.txt 13 | ``` 14 | 15 | You may need to install these libraries for a correct installation of all dependencies: 16 | 17 | libxsl1-dev 18 | libxml2-dev 19 | 20 | **Note**: libraries refer on Ubuntu package name, please search an equivalent for yours OS. 21 | 22 | ## How to test 23 | 24 | Just type the command below in the main directory: 25 | 26 | ```bash 27 | honcho start 28 | ``` 29 | 30 | You can see the example page at `http://localhost:5000/` with your browser. 31 | WSDL generated on `http://localhost:5000/soap?wsdl`. 32 | 33 | **Note**: internet connection is required to download jquery library. 34 | 35 | ## Authors 36 | 37 | [Gabriele](https://github.com/Gabriele91) 38 | [Mirco](https://github.com/MircoT) 39 | 40 | ## License 41 | 42 | The MIT License (MIT) 43 | 44 | Copyright (C) 2013 Gabriele Di Bari, Mirco Tracolli 45 | 46 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 47 | 48 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 49 | 50 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 51 | -------------------------------------------------------------------------------- /app.py: -------------------------------------------------------------------------------- 1 | #python lib 2 | import os 3 | #flask lib 4 | from flaskext.enterprise import Enterprise 5 | from flask import Flask, render_template 6 | 7 | #config Flask 8 | app = Flask(__name__) 9 | 10 | #config Flask Enterprise 11 | enterprise = Enterprise(app) 12 | String = enterprise._sp.String 13 | Integer = enterprise._sp.Integer 14 | Boolean = enterprise._sp.Boolean 15 | Array = enterprise._scls.Array 16 | 17 | class Service(enterprise.SOAPService): 18 | """Soap Service Class 19 | 20 | Attributes: 21 | __soap_target_namespace__ : namespace for soap service 22 | __soap_server_address__ : address of soap service 23 | """ 24 | __soap_target_namespace__ = 'MyNS' 25 | __soap_server_address__ = '/soap' 26 | 27 | @enterprise.soap(String, _returns=String) 28 | def echo(self, mystring): 29 | """ Function that return the string in args 30 | 31 | Args: 32 | mystring : string 33 | 34 | Returns: 35 | return a string 36 | """ 37 | return mystring 38 | 39 | @enterprise.soap(Integer, Integer, _returns=Integer) 40 | def sum(self, x, y): 41 | """ Function to sum two integer 42 | 43 | Args: 44 | x : int 45 | y : int 46 | 47 | Returns: 48 | return an int 49 | """ 50 | return x+y 51 | 52 | @enterprise.soap(Integer, Integer, _returns=Boolean) 53 | def equal(self, x, y): 54 | """ Function to compare two integer 55 | 56 | Args: 57 | x : int 58 | y : int 59 | 60 | Returns: 61 | return a boolean 62 | """ 63 | return x==y 64 | 65 | @enterprise.soap(Integer, _returns=Array(Integer)) 66 | def createArray(self, lenA): 67 | """ Function to create an array of integer 68 | 69 | Args: 70 | lenA : int 71 | 72 | Returns: 73 | return an array 74 | """ 75 | return [int(x) for x in range(1,lenA+1)] 76 | 77 | @app.route('/') 78 | def pageIndex(): 79 | """ The index page 80 | """ 81 | return render_template("index.html") 82 | 83 | @app.errorhandler(404) 84 | def page_not_found(e): 85 | """ Error 404 86 | """ 87 | return render_template("404.html"), 404 88 | 89 | @app.errorhandler(403) 90 | def forbidden(e): 91 | """ Error 403 92 | """ 93 | return render_template("403.html"), 403 94 | 95 | @app.errorhandler(410) 96 | def gone(e): 97 | """ Error 410 98 | """ 99 | return render_template("410.html"), 410 100 | 101 | @app.errorhandler(500) 102 | def internal_server_error(e): 103 | """ Error 500 104 | """ 105 | return render_template("500.html"), 500 106 | 107 | if __name__ == '__main__': 108 | # Bind to PORT if defined, otherwise default to 5000. 109 | port = int(os.environ.get('PORT', 5000)) 110 | app.debug = True 111 | app.run(host='0.0.0.0', port=port) 112 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | Flask==2.3.2 2 | Flask-Enterprise==1.0 3 | Jinja2==2.11.3 4 | Werkzeug==2.2.3 5 | argparse==1.2.1 6 | distribute 7 | honcho==0.3.1 8 | lxml 9 | pytz==2013b 10 | soaplib==2.0.0-beta2 11 | suds==1.0.0 12 | wsgiref==0.1.2 13 | -------------------------------------------------------------------------------- /static/SoapApi.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Function that convert an xml to json 3 | * @author http://davidwalsh.name/convert-xml-json 4 | * @param {string} xml an xml object string 5 | * @return {string} obj a json dictionary 6 | * @fileoverview Simple function to convert xml to json 7 | */ 8 | function xmlToJson(xml) { 9 | // Create the return object 10 | var obj = {}; 11 | if (xml.nodeType == 1) { // element 12 | // do attributes 13 | if (xml.attributes.length > 0) { 14 | obj["@attributes"] = {}; 15 | for (var j = 0; j < xml.attributes.length; j++) { 16 | var attribute = xml.attributes.item(j); 17 | obj["@attributes"][attribute.nodeName] = attribute.nodeValue; 18 | } 19 | } 20 | } else if (xml.nodeType == 3) { // text 21 | obj = xml.nodeValue; 22 | } 23 | // do children 24 | if (xml.hasChildNodes()) { 25 | for(var i = 0; i < xml.childNodes.length; i++) { 26 | var item = xml.childNodes.item(i); 27 | var nodeName = item.nodeName; 28 | if (typeof(obj[nodeName]) == "undefined") { 29 | obj[nodeName] = xmlToJson(item); 30 | } else { 31 | if (typeof(obj[nodeName].push) == "undefined") { 32 | var old = obj[nodeName]; 33 | obj[nodeName] = []; 34 | obj[nodeName].push(old); 35 | } 36 | obj[nodeName].push(xmlToJson(item)); 37 | } 38 | } 39 | } 40 | return obj; 41 | }; 42 | /** 43 | * Function to call to write soap messages on console 44 | * @param {String} title 45 | * @return {String} messageXML : can be a string or an xml object 46 | */ 47 | function messageLog(title,messageXML) { 48 | var xml = $.parseXML(messageXML); 49 | if (xml == null) { 50 | var message = JSON.stringify(xmlToJson(messageXML),null," "); 51 | console.log(title+" = "+message); 52 | } 53 | else{ 54 | var message = JSON.stringify(xmlToJson(xml),null," "); 55 | console.log(title+" = "+message); 56 | } 57 | } 58 | /** 59 | * @author Gabriele Di Bari 60 | * @author Mirco Tracolli 61 | * @fileoverview JQUERY is required 62 | */ 63 | /** 64 | * site web url 65 | * defaultUrl : according do app.py __soap_server_address__ 66 | */ 67 | var defaultUrl = window.location.protocol+"//"+window.location.host+"/soap"; 68 | /** 69 | * Class that contain Soap functions 70 | * @param {string} urlSoapServer the url of the soap web server 71 | * @constructor 72 | */ 73 | function SoapApi(urlSoapServer) { 74 | /** 75 | * Constructor for a singleton 76 | */ 77 | if ( SoapApi.prototype._singletonInstance ){ 78 | if(!(typeof urlSoapServer === 'undefined' || urlSoapServer==null)) 79 | this.SOAPSERVER = urlSoapServer; 80 | return SoapApi.prototype._singletonInstance; 81 | } 82 | /** 83 | * first call save object in singleton istance 84 | */ 85 | SoapApi.prototype._singletonInstance = new objectSoapApi(urlSoapServer); 86 | return SoapApi.prototype._singletonInstance; 87 | /** 88 | * An object that can manage soap 89 | * @param {string} urlSoapServer the url of the soap web server 90 | */ 91 | function objectSoapApi(urlSoapServer){ 92 | /** 93 | * if is not def set default url 94 | */ 95 | if(!(typeof urlSoapServer === 'undefined' || urlSoapServer==null)) 96 | this.SOAPSERVER = urlSoapServer; 97 | else 98 | this.SOAPSERVER = defaultUrl 99 | /** 100 | * Some constant variables with parameters that will be replaced 101 | * @constant 102 | * @type String 103 | */ 104 | this.METHODE = ""; 105 | this.METHODECLOSE = ""; 106 | this.ARGE = "VALUE"; 107 | /** 108 | * Variable that will contain results 109 | * @type {Dict} 110 | */ 111 | this.result = {}; 112 | 113 | this.createSoapMessage = function (namespace, method, args) { 114 | /** 115 | * Function to create a soap message 116 | * @param {String} namespace 117 | * @param {String} method 118 | * @param {Dict} args { varName : [elementType,elementValue] } 119 | * @returns {Dict} { message : soapMessage, tagResponse : String , tagResult : String, ns : String} 120 | */ 121 | var soapMessage = ""; 122 | soapMessage += " " + errorThrown); 190 | }); 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /static/normalize.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v2.1.0 | MIT License | git.io/normalize */ 2 | 3 | /* ========================================================================== 4 | HTML5 display definitions 5 | ========================================================================== */ 6 | 7 | /** 8 | * Correct `block` display not defined in IE 8/9. 9 | */ 10 | 11 | article, 12 | aside, 13 | details, 14 | figcaption, 15 | figure, 16 | footer, 17 | header, 18 | hgroup, 19 | main, 20 | nav, 21 | section, 22 | summary { 23 | display: block; 24 | } 25 | 26 | /** 27 | * Correct `inline-block` display not defined in IE 8/9. 28 | */ 29 | 30 | audio, 31 | canvas, 32 | video { 33 | display: inline-block; 34 | } 35 | 36 | /** 37 | * Prevent modern browsers from displaying `audio` without controls. 38 | * Remove excess height in iOS 5 devices. 39 | */ 40 | 41 | audio:not([controls]) { 42 | display: none; 43 | height: 0; 44 | } 45 | 46 | /** 47 | * Address styling not present in IE 8/9. 48 | */ 49 | 50 | [hidden] { 51 | display: none; 52 | } 53 | 54 | /* ========================================================================== 55 | Base 56 | ========================================================================== */ 57 | 58 | /** 59 | * 1. Set default font family to sans-serif. 60 | * 2. Prevent iOS text size adjust after orientation change, without disabling 61 | * user zoom. 62 | */ 63 | 64 | html { 65 | font-family: sans-serif; /* 1 */ 66 | -webkit-text-size-adjust: 100%; /* 2 */ 67 | -ms-text-size-adjust: 100%; /* 2 */ 68 | } 69 | 70 | /** 71 | * Remove default margin. 72 | */ 73 | 74 | body { 75 | margin: 0; 76 | } 77 | 78 | /* ========================================================================== 79 | Links 80 | ========================================================================== */ 81 | 82 | /** 83 | * Address `outline` inconsistency between Chrome and other browsers. 84 | */ 85 | 86 | a:focus { 87 | outline: thin dotted; 88 | } 89 | 90 | /** 91 | * Improve readability when focused and also mouse hovered in all browsers. 92 | */ 93 | 94 | a:active, 95 | a:hover { 96 | outline: 0; 97 | } 98 | 99 | /* ========================================================================== 100 | Typography 101 | ========================================================================== */ 102 | 103 | /** 104 | * Address variable `h1` font-size and margin within `section` and `article` 105 | * contexts in Firefox 4+, Safari 5, and Chrome. 106 | */ 107 | 108 | h1 { 109 | font-size: 2em; 110 | margin: 0.67em 0; 111 | } 112 | 113 | /** 114 | * Address styling not present in IE 8/9, Safari 5, and Chrome. 115 | */ 116 | 117 | abbr[title] { 118 | border-bottom: 1px dotted; 119 | } 120 | 121 | /** 122 | * Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. 123 | */ 124 | 125 | b, 126 | strong { 127 | font-weight: bold; 128 | } 129 | 130 | /** 131 | * Address styling not present in Safari 5 and Chrome. 132 | */ 133 | 134 | dfn { 135 | font-style: italic; 136 | } 137 | 138 | /** 139 | * Address differences between Firefox and other browsers. 140 | */ 141 | 142 | hr { 143 | -moz-box-sizing: content-box; 144 | box-sizing: content-box; 145 | height: 0; 146 | } 147 | 148 | /** 149 | * Address styling not present in IE 8/9. 150 | */ 151 | 152 | mark { 153 | background: #ff0; 154 | color: #000; 155 | } 156 | 157 | /** 158 | * Correct font family set oddly in Safari 5 and Chrome. 159 | */ 160 | 161 | code, 162 | kbd, 163 | pre, 164 | samp { 165 | font-family: monospace, serif; 166 | font-size: 1em; 167 | } 168 | 169 | /** 170 | * Improve readability of pre-formatted text in all browsers. 171 | */ 172 | 173 | pre { 174 | white-space: pre-wrap; 175 | } 176 | 177 | /** 178 | * Set consistent quote types. 179 | */ 180 | 181 | q { 182 | quotes: "\201C" "\201D" "\2018" "\2019"; 183 | } 184 | 185 | /** 186 | * Address inconsistent and variable font size in all browsers. 187 | */ 188 | 189 | small { 190 | font-size: 80%; 191 | } 192 | 193 | /** 194 | * Prevent `sub` and `sup` affecting `line-height` in all browsers. 195 | */ 196 | 197 | sub, 198 | sup { 199 | font-size: 75%; 200 | line-height: 0; 201 | position: relative; 202 | vertical-align: baseline; 203 | } 204 | 205 | sup { 206 | top: -0.5em; 207 | } 208 | 209 | sub { 210 | bottom: -0.25em; 211 | } 212 | 213 | /* ========================================================================== 214 | Embedded content 215 | ========================================================================== */ 216 | 217 | /** 218 | * Remove border when inside `a` element in IE 8/9. 219 | */ 220 | 221 | img { 222 | border: 0; 223 | } 224 | 225 | /** 226 | * Correct overflow displayed oddly in IE 9. 227 | */ 228 | 229 | svg:not(:root) { 230 | overflow: hidden; 231 | } 232 | 233 | /* ========================================================================== 234 | Figures 235 | ========================================================================== */ 236 | 237 | /** 238 | * Address margin not present in IE 8/9 and Safari 5. 239 | */ 240 | 241 | figure { 242 | margin: 0; 243 | } 244 | 245 | /* ========================================================================== 246 | Forms 247 | ========================================================================== */ 248 | 249 | /** 250 | * Define consistent border, margin, and padding. 251 | */ 252 | 253 | fieldset { 254 | border: 1px solid #c0c0c0; 255 | margin: 0 2px; 256 | padding: 0.35em 0.625em 0.75em; 257 | } 258 | 259 | /** 260 | * 1. Correct `color` not being inherited in IE 8/9. 261 | * 2. Remove padding so people aren't caught out if they zero out fieldsets. 262 | */ 263 | 264 | legend { 265 | border: 0; /* 1 */ 266 | padding: 0; /* 2 */ 267 | } 268 | 269 | /** 270 | * 1. Correct font family not being inherited in all browsers. 271 | * 2. Correct font size not being inherited in all browsers. 272 | * 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. 273 | */ 274 | 275 | button, 276 | input, 277 | select, 278 | textarea { 279 | font-family: inherit; /* 1 */ 280 | font-size: 100%; /* 2 */ 281 | margin: 0; /* 3 */ 282 | } 283 | 284 | /** 285 | * Address Firefox 4+ setting `line-height` on `input` using `!important` in 286 | * the UA stylesheet. 287 | */ 288 | 289 | button, 290 | input { 291 | line-height: normal; 292 | } 293 | 294 | /** 295 | * Address inconsistent `text-transform` inheritance for `button` and `select`. 296 | * All other form control elements do not inherit `text-transform` values. 297 | * Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. 298 | * Correct `select` style inheritance in Firefox 4+ and Opera. 299 | */ 300 | 301 | button, 302 | select { 303 | text-transform: none; 304 | } 305 | 306 | /** 307 | * 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` 308 | * and `video` controls. 309 | * 2. Correct inability to style clickable `input` types in iOS. 310 | * 3. Improve usability and consistency of cursor style between image-type 311 | * `input` and others. 312 | */ 313 | 314 | button, 315 | html input[type="button"], /* 1 */ 316 | input[type="reset"], 317 | input[type="submit"] { 318 | -webkit-appearance: button; /* 2 */ 319 | cursor: pointer; /* 3 */ 320 | } 321 | 322 | /** 323 | * Re-set default cursor for disabled elements. 324 | */ 325 | 326 | button[disabled], 327 | html input[disabled] { 328 | cursor: default; 329 | } 330 | 331 | /** 332 | * 1. Address box sizing set to `content-box` in IE 8/9. 333 | * 2. Remove excess padding in IE 8/9. 334 | */ 335 | 336 | input[type="checkbox"], 337 | input[type="radio"] { 338 | box-sizing: border-box; /* 1 */ 339 | padding: 0; /* 2 */ 340 | } 341 | 342 | /** 343 | * 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. 344 | * 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome 345 | * (include `-moz` to future-proof). 346 | */ 347 | 348 | input[type="search"] { 349 | -webkit-appearance: textfield; /* 1 */ 350 | -moz-box-sizing: content-box; 351 | -webkit-box-sizing: content-box; /* 2 */ 352 | box-sizing: content-box; 353 | } 354 | 355 | /** 356 | * Remove inner padding and search cancel button in Safari 5 and Chrome 357 | * on OS X. 358 | */ 359 | 360 | input[type="search"]::-webkit-search-cancel-button, 361 | input[type="search"]::-webkit-search-decoration { 362 | -webkit-appearance: none; 363 | } 364 | 365 | /** 366 | * Remove inner padding and border in Firefox 4+. 367 | */ 368 | 369 | button::-moz-focus-inner, 370 | input::-moz-focus-inner { 371 | border: 0; 372 | padding: 0; 373 | } 374 | 375 | /** 376 | * 1. Remove default vertical scrollbar in IE 8/9. 377 | * 2. Improve readability and alignment in all browsers. 378 | */ 379 | 380 | textarea { 381 | overflow: auto; /* 1 */ 382 | vertical-align: top; /* 2 */ 383 | } 384 | 385 | /* ========================================================================== 386 | Tables 387 | ========================================================================== */ 388 | 389 | /** 390 | * Remove most spacing between table cells. 391 | */ 392 | 393 | table { 394 | border-collapse: collapse; 395 | border-spacing: 0; 396 | } 397 | -------------------------------------------------------------------------------- /templates/403.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Forbidden 5 | 6 | 7 |

Page Forbidden

8 |

What you were looking for is not accessible. 9 |

go somewhere nice 10 | 11 | -------------------------------------------------------------------------------- /templates/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Not Found 5 | 6 | 7 |

Page Not Found

8 |

What you were looking for is just not there. 9 |

go somewhere nice 10 | 11 | -------------------------------------------------------------------------------- /templates/410.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Page Gone 5 | 6 | 7 |

Page Gone

8 |

What you were looking for is no longer avaible. 9 |

go somewhere nice 10 | 11 | -------------------------------------------------------------------------------- /templates/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Internal Server Error 5 | 6 | 7 |

Internal Server Error

8 |

There are some errors, please contact the administrators! 9 |

go to home page 10 | 11 | -------------------------------------------------------------------------------- /templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Flask Soap Server 5 | 6 | 7 | 8 | 44 | 45 | 46 |

47 |
48 |
49 | string 50 |
51 |
52 | X value 53 |
54 |
55 | Y value 56 |
57 |
58 |
59 | 60 |
61 |
echo(string) :
62 |
sum(X,Y) :
63 |
equal(X,Y) :
64 |
createArray(X) :
65 |
66 |
67 | 68 | 69 | --------------------------------------------------------------------------------