QEWD.js
react-qewd: React/Redux client module forInterface module for writing React applications with qewd (QEWD.js) back-end. Exposes the ewd-client as object, in React context and as property for use in your React components.
A similar module vue-qewd exists for Vue.js.
QEWD.js is a unique web framework allowing you to concentrate on your application code, without worrying about system infrastructure, featuring:
- a WebSockets server, allowing your application to connect via this
vue-qewd
module using ewd-client - a (federating) REST server, to build your REST endpoints & allowing you to federate requests to other (chained) QEWD servers, featuring Express or Koa as underlying frameworks
- a microservices server, using very efficient (permanent, secured) WebSocket connections to other QEWD servers using JWT's
- a GraphQL server to write & process your GraphQL queries & mutations
- an application router to orchestrate all your different application endpoint(s)/handler(s)
- a master/worker multi-process queue architecture, high-performance and very scalable
- session management/cache allowing you to write stateful applications
- response customization: combine responses from different servers, return responses in different formats, intercept an re-route requests, ...
- built-in JSON database abstraction: make your application data persistent using the InterSystems Caché multi-model database or the InterSystems IRIS Data platform (unified data access as a document/NoSQL store or using SQL or objects), Redis, YottaDB, ...
Thanks to Rob Tweed for providing the qewd-react module this interface module code is based on.
Installing
npm install react-qewd
Version 2: breaking changes!
From version 2.0.0 onwards, the socket.io-client and jQuery module dependencies for the underlying ewd-client need to be passed in as parameters when instantiating QEWD:
let qewd =
Overview of parameter changes in 2.0.0 and up:
io
was added: required for WebSocket communication mode, import it as above or as
var io =
$
was added: required for Ajax communication mode using the jQuery ajax method, import it as above or as
var $ =
ajax
remains the same: required for Ajax communication mode, using you own custom Ajax module, e.g. with axios
// import $ from 'jquery' var qewd =
- for mixed WebSocket & Ajax communication mode, you need both parameters (io and $ || ajax)
no_sockets
parameter was removeduse_jquery
parameter was removed
This allows you to control which modules you need and avoids Webpack dependency detection issues.
Options
Options you can pass to the QEWD({ ... })
instance (see examples) with their default values and a short description:
{
// application module name
application: 'unknown',
// socket.io-client module (optional, required for WebSockets communication)
io: undefined,
// jquery module (optional, required for Ajax communication using jQuery's $.ajax)
$: undefined,
// specify your own Ajax request handler function, see example above (optional)
ajax: null,
// url of QEWD.js server, in the form 'http(s)://<host>:<port>'
url: null,
// runtime mode for ewd-client (optional)
mode: 'development',
// log each QEWD message sent & received on console (optional)
log: true,
// specify custom cookie name to restart the current WebSockets session between page refreshes (optional)
cookieName: 'ewdSession',
// use JWT's for sessions (optional)
jwt: false,
// decode JWT's in the client (optional)
jwt_decode: false
}
You'll find further details about these options in the QEWD.js training course.
React
Use withWith React components and/or Redux and Redux Thunk middleware, you can start from this example in your source code (just create a standard create-react-app template first).
Install some dependencies:
npm install redux react-redux redux-thunk bootstrap react-bootstrap react-spinner react-toastr
First, modify index.js:
;;;;;;;;;;;;; let qewd = ; // we instantiate this object to pass the EWD 3 client to the Redux action methods in actions/*.jslet extraThunkArgument = qewd ; /* instantiate the Redux store with thunk middleware, this allows to dispatch actions asynchronously devToolsExtension is needed to enable Redux DevTools for debugging in the browser*/const store = ; // main QEWD React container component (similar to the Top component in the qewd-react loader) { let styles = MainDiv: padding: 20 Spinner: width: '100%' height: 100 ; /* instantiate the Redux Provider with its store as property before the connection to the QEWD server is registered, a waiting Spinner is shown once the connection is registered, React renders our <App> */ return <Provider store=store> <div style=stylesMainDiv> propsqewdProviderStateregistered ? <App qewd=qewd /> : <div style=stylesSpinner> <Spinner /> </div> </div> </Provider> } /* main starting point of your React/Redux application instantiates the QEWDProvider component where the qewd client instance is passed in as a property (for use in your components)*/;
Next, modify the App component in components/App.js:
;;;;;;; // our main App component, contains the main App functionalityComponent static propTypes = dispatch: PropTypesfuncisRequired { superprops; // bind handleSubmit to App component scope thishandleSubmit = thishandleSubmit; } { // load and augment the ewd client for this module... let qewd = thisprops; const component = this; // add toast container to ewd client to display warnings qewd { if type && type !== '' && component_toastContainer && component_toastContainertype component_toastContainertypetext; }; // shortcut method for displaying errors qewd { qewd; }; } { const qewd = thisprops; console; qewd; } { const dispatch = thisprops; // prevent default form submitting by browser e; // pick up message text value entered by user const message = this_messageInputvalue; if message // dispatch a requestQEWDMessage action to actions/tests.js ; this_messageInputvalue = ''; } { const ToastMessageFactory = ; const messageText = thisprops; // instantiate ToastContainer component for displaying warnings to the user // add a small form containing the message text input, add a reference to the textinput to the <App> component for handleSubmit() // display the messageText we received from teh EWD 3 server and show it, this property is updated by changing the state in reducers/index.js // because state.messageText is mapped to the messageText prop (see last line), the UI will be updated by React return <span> <ToastContainer ref= { this_toastContainer = c; } // strings refs are deprecated toastMessageFactory=ToastMessageFactory className="toast-top-right" newestOnTop=true target="body" /> <div> <form onSubmit= this> <FormGroup> <ControlLabel>Message to QEWD back-end:</ControlLabel> <input className="form-control" type="text" placeholder="Enter message" ref= {this_messageInput = c} /> </FormGroup> </form> <div> <b>Message from QEWD back-end: messageText</b> </div> </div> </span> ; } // create a mapStateToProps function to create a property object (identical to the state content here)const mapStateToProps = ...state ; // connect with Redux the internal/immutable Redux state to the props of the <App> componentmapStateToPropsApp;
Next, create Redux action types in constants/ActionTypes.js:
// define your action types as string constants for easy maintenanceconst REQUEST_QEWD_MESSAGE = 'REQUEST_QEWD_MESSAGE';const RECEIVE_QEWD_MESSAGE = 'RECEIVE_QEWD_MESSAGE';
Next, create Redux actions in actions/tests.js:
; // message request action: post message text to EWD 3 back-end using ewd.send()// sending is asynchronous, when ewd.send() completes, a second receiveQEWDMessage action is dispatched// notice the qewd client is passed in by the Redux thunk middleware by destructuring the extraArgument { qewd }const requestQEWDMessage = { return { let messageObj = type: 'test' //ajax: true, params: text: text ; qewd; }}; // return the message text received from EWD 3 synchronously as an action object// to the Redux reducer (in reducers/index.js), is passed in there as action objectconst receiveQEWDMessage = { //console.log('message: ', message); var text = message ? messagetext || '' : '' || ''; return type: typesRECEIVE_QEWD_MESSAGE text };
Next, create reducers in reducers/index.js:
;; // define a messageText reducer method called by Redux// modifies the state object in Redux// you need to return a new state always and the action data needs to be copied to the state// for complex data structures like objects, arrays, ..., use deepAssign method from immutableJS { } // all (sub)reducers must be combined to one single reducer// Redux creates only one store for the whole application messageText;
Next, create styling in styles/app.scss:
;;;;
Next, create styling in styles/_base.scss:
Next, create styling in styles/_react-spinner.scss:
@ 100% } @- 100% } @- 100% }
Next, add styling in App.css:
@}
Next, add styling in index.css:
Finally, start the test application:
npm start
License
Copyright (c) 2019 Stabe nv,
Hofstade, Oost-Vlaanderen, BE
All rights reserved
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.