Swagger-editor: save to backend

Created on 28 Mar 2017  路  13Comments  路  Source: swagger-api/swagger-editor

In the new V3 version there is no option "useBackendForStorage, backendEndpoint" to set an endpoint to save the json:

https://github.com/swagger-api/swagger-editor/blob/2.x/docs/config.md#backends

Is the feature in roadmap?

P2 feature 3.x

Most helpful comment

For those interested, I've written a wrapper package for the swagger-editor 3.x https://www.npmjs.com/package/openapi-editor It uses a similar solution as described by @jemerald

All 13 comments

You can use dirty hack, just replace src/plugins/local-storage/index.js with

```import PetstoreYaml from "./petstore"
const CONTENT_KEY = "swagger-editor-content"

let localStorage = window.localStorage

export const updateSpec = (ori) => (...args) => {
let [spec] = args
ori(...args)
saveContentToStorage(spec)
}

export default function(system) {
// setTimeout runs on the next tick
setTimeout(() => {

var xhr = new XMLHttpRequest();

xhr.open('GET', BACKEND_URL, false);
xhr.send();
if (xhr.status != 200) {
console.log( xhr.status + ': ' + xhr.statusText );
} else {
system.specActions.updateSpec(xhr.responseText)
}

}, 0)
return {
statePlugins: {
spec: {
wrapActions: {
updateSpec
}
}
}
}
}

function saveContentToStorage(str) {
var xhr = new XMLHttpRequest();
xhr.open('PUT', BACKEND_URL, true);
xhr.send(str);

if (xhr.status != 200) {
console.log( xhr.status + ': ' + xhr.statusText );
}
}

```

don't forget change BACKEND_URL. Next step - edit src/plugins/editor/components/editor-container.jsx and update DEBOUNCE_TIME it's delay time before save, 800 ms too fast for me :)

I subscribe to the expected realization of save to backend

Where are the docs for Editor 3.x?

With the help of the hints in https://github.com/swagger-api/swagger-editor/issues/1471, I've got the "saving to backend" feature working with a modified index.html that is identical to the one comes with swagger-editor-dist but with the following scripts:

<script>
  function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
  }
  const SpecUpdateListenerPlugin = function() {
    return {
      statePlugins: {
        spec: {
          wrapActions: {
            updateSpec: function(oriAction) {
              return function(spec) {
                var url = getParameterByName('url');
                var xhr = new XMLHttpRequest();
                xhr.open('PUT', url, true);
                xhr.send(spec);

                if (xhr.status != 200) {
                  console.log( xhr.status + ': ' + xhr.statusText );
                }
                return oriAction(spec);
              };
            }
          }
        }
      }
    }
  }
  window.onload = function() {
    // Build a system
    const editor = SwaggerEditorBundle({
      dom_id: '#swagger-editor',
      layout: 'StandaloneLayout',
      presets: [
        SwaggerEditorStandalonePreset
      ],
      plugins: [
        SpecUpdateListenerPlugin
      ]
    });

    window.editor = editor;
  }
  </script>

I have the modified editor served on http://localhost/editor and all my spec on http://localhost/specs (with GET and PUT). Then the link to edit a specification is http://localhost/editor/?url=/specs/file.yaml

Hi Jemerald,

Thanks for the solution given to edit the document on server. I have followed the steps you mentioned above but I have observed that in browser console its showing "Failed to load resource: the server responded with a status of 403 (Forbidden)" when trying to execute the method xhr.send(spec). Can you please help me is there any solution to fix the 403 error.

Regards,
Suresh

@sureshui18 the 403 error would come from your webserver and has nothing to do with the code above.

You will need to make sure you can access the yaml files served by your webserver. Try test it with curl or similar tools

@jemerald, I am trying to understand your comment above "I've got the "saving to backend" feature working ".

Am I right to understand that you did:
1) npm i swagger-editor-dist
2) Modified ./node_modules/swagger-editor-dist/index.html, replacing the window.onLoad script with what you included above.

I have swagger-editor-dist working, I tried the modification suggested above. swagger-editor still works, but when I select the menu option "File -> Save as JSON", the browser still downloads the swagger as a JSON, instead of trying to store it to a backend.

I guess I am missing something.

Hey @MattGurneyAMP, @jemerald's plugin above automatically sends requests when Swagger Editor's content changes, not when the File menu is used 馃槃

Thanks @shockey, that is useful to know. However, I am at a loss to understand what changes I have to make to either the github source of swagger-editor or the npm distribution of swagger-editor-dist to enable the write to backend feature. I know how to setup my own node express backend to serve and save swagger files. I just don't know how to make swagger-editor call it during saving (which you tell me is triggered when editor content changes). I use the url= feature to open swagger files in the editor, and I serve those from my node express server successfully.

Just guessing, but do I need to make the change to src/plugins/local-storage/index.js, as suggested by @iromanov-nk, then make the change to the src file representing ./node_modules/swagger-editor-dist/index.html as suggested by @jemerald ?

@MattGurneyAMP my post above already included the setup. Here's how things work under the hood:

  1. User open browser to http://localhost/editor/?url=/specs/file.yaml (if the specs is hosted on a different server from the editor, just need to include the full URL: http://localhost/editor/?url=http://server2/specs/file.yaml)
  2. The modified index.html is served
  3. Swagger UI/Editor downloads the spec by issuing AJAX request GET http://localhost/specs/file.yaml
  4. User makes changes in the editor
  5. The plugin code saves the spec by issuing AJAX request PUT http://localhost/specs/file.yaml with the body being the entire payload

Server side code would handle GET/PUT methods on path /specs/* to do the reading and writing of files. Mine is just a simple express server:

    var route = app.route(`/specs/*`);
    route.get(function (req, res) {
        // substring(1) removes the initial slash and turns it into relative path, which matches the folder structure on the server
        let path = decodeURI(req.path).substring(1);
        res.send(fs.readFileSync(path));
    });
    route.put(function (req, res) {
        let path = decodeURI(req.path).substring(1);
        let rawBody = '';
        req.on('data', function(chunk) {
            rawBody += chunk;
        });
        req.on('end', function(){
            fs.writeFileSync(path, rawBody);
            res.send(fs.readFileSync(path));
        });
    });

Thanks @jemerald, I understand, it is working now. This is a great feature. What I didn't understand before is that I can use either the packaged swagger-editor-dist or the full source and the only code change needed was to change node_modulesswagger-editor-distindex.html (or equivalent unpackaged source), and replace the window.onLoad script with what you included above.

Additionally as you mention above a simple node express server is needed to act as the backend.

Sorry for any confusion and thanks again for your help and a great project :).

I may attempt to extend this solution to integrate into a more fully featured backend with more of a workflow around versioning, update history, save on demand instead of automatic etc. If anyone has any ideas on a npm project which could act as the back end Content Management System, let me know.

@MattGurneyAMP check out Netlify CMS, which lives under version control and already stores its data in YAML. Not sure if they have the necessary APIs for automated modification though.

Ok, thanks @shockey will do.

For those interested, I've written a wrapper package for the swagger-editor 3.x https://www.npmjs.com/package/openapi-editor It uses a similar solution as described by @jemerald

Was this page helpful?
0 / 5 - 0 ratings

Related issues

gerbsen picture gerbsen  路  3Comments

radj picture radj  路  5Comments

delim29 picture delim29  路  4Comments

SteveNewhouse picture SteveNewhouse  路  5Comments

variable picture variable  路  4Comments