Coder Social home page Coder Social logo

restforms's Introduction

RESTForms

RESTForms is a generalized REST API backend for web applications built on InterSystems (Caché or Ensemble) backend.

Installation

  1. Import latest release appropriate for your Caché version (161 for 2016.1, 162 for 2016.2+).
  2. Create REST web app with Form.REST.Main as Dispatch Class.
  3. Generate test data: do ##class(Form.Util.Init).populateTestForms()

Usage description and examples

Read this post on Developer Community. Developer community article about queries. Russian article.

Requests

URL Type Description
test GET Test request
info GET Basic information (currently language list)
logout GET End current session
form/info GET List of all availible forms
form/info/all GET Get metainformation for all forms
form/info/:class GET Form metainformation
form/field/:class POST Add field to form
form/field/:class PUT Modify form field
form/field/:class/:property DELETE Delete form field
form/object/:class/:id GET Retrieve form object
form/object/:class/:id/:property GET Retrieve one field of the form object
form/object/:class POST Create form object
form/object/:class/:id PUT Update form object from dynamic object
form/object/:class PUT Update form object from object
form/object/:class/:id DELETE Delete form object
form/objects/:class/:query GET (SQL) Get all members for the form by query
form/objects/:class/custom/:query GET (SQL) Get all members for the form by custom query
form/file/:class/:id/:property POST Add files to this property
form/file/:class/:id/:property DELETE Delete all files from this property
form/file/:class/:id/:property/:name DELETE Delete one file from property
form/file/:class/:id/:property/:name GET Download one file from property

For POST/PUT requests see method descriptions for request body samples

Postman

You can use Postman to query RESTForms API. Collection. Environment.

SQL requests

GET http://localhost:57772/forms/form/objects/Form.Test.Simple/info?size=2&page=1&orderby=text

GET http://localhost:57772/forms/form/objects/Form.Test.Simple/all?orderby=text+desc

GET http://localhost:57772/forms/form/objects/Form.Test.Simple/all?filter=text%20eq%20A9044

GET http://localhost:57772/forms/form/objects/Form.Test.Simple/all?filter=text%20in%20A9044~B5920

Note, that for SQL access user must have relevant SQL privileges (SELECT on form table).

Queries

There are two query types:

  • Basic queries work for all RESTForms classes once defined and they differ only by the field list
  • Custom queries work only for the classes in which they are specified and available, but the user has full access to query text

Basic queries

Execute form/objects/:class/:query request, to call a simple query. Second :query parameter determines query type - the contents of query between SELECT and FROM. Here are default query types:

Query Description
all all information
info displayName and id
infoclass displayName, id, class
count number of rows

RESTForms looks for a query named myq in the following places (till first hit):

  1. Class method queryMYQ in your form class
  2. Parameter MYQ in your queries class
  3. Class method queryMYQ in your queries class
  4. Parameter MYQ in Form.REST.Objects class
  5. Class method queryMYQ in Form.REST.Objects class

You can define your own queries class. To define your own query named myq there:

  1. Define a class YourClassName
  2. Define there a MYQ parameter or queryMYQ class method. Parameter takes precedence over the method.
  3. Method or param must return the part of SQL query between SELECT and FROM
  4. (Once) Execute in a terminal: Do ##class(For.Settings).setSetting("queryclass", YourClassName)

Method signature is: ClassMethod queryMYQ(class As %String) As %String

You can define a class-specific query. To define your own class query named myq:

  1. Define a queryMYQ class method in your form class
  2. Method signature is: ClassMethod queryMYQ() As %String
  3. Method must return the part of SQL query between SELECT and FROM

Custom Queries

Execute form/objects/:class/custom/:query request, to call a custom query. Custom query allows user code to determine the full content of the query. URL parameters besides size and page are unavailable. Your method must parse all other url parameters.

To define your own custom query named myq:

  1. Define a customqueryMYQ class method in your form class
  2. Method signature is: ClassMethod customqueryMYQ() As %String
  3. Method must return a valid SQL query

URL arguments:

All arguments are optional.

Argument Sample Value Description
size 2 page size
page 1 page number
filter Value+contains+W WHERE clause
orderby Value+desc ORDER BY clause
collation UPPER COLLATION clause
nocount 1 Remove count of rows (speeds up query)
mode 0 SQL mode value. Can be 0 - Logical, 1 - ODBC, 2 - Display. Defaults to 0.

ORDER BY clause

Value can be: Column or Column+desc. Column is a column from the sql table or a colum number.

WHERE clause

In a format: Column+condition+Value.

Several conditions are possible: Column+condition+Value+Column2+condition2+Value2.

If Value contains white spaces replace them with tabs before sending to the server.

Conditions:

URL SQL
neq !=
eq =
gte >=
gt >
lte <=
lt <
startswith %STARTSWITH
contains [
doesnotcontain '[
in IN
like LIKE

COLLATION clause

In a format: collation=UPPER or collation=EXACT. Forces specified collation on WHERE clause. If omitted, default collation is used.

Settings

You can setup several settings. Set them via Write ##class(For.Settings).setSetting(Setting, Value).

Setting Values Description
queryclass Caché class name Class with your own queries. See Query types for details.
fileDir Directory path Directory for files. Defaults to MGR\DB directory
timezone ignore, utc Affects how timestamps are converted for a client. UTC has Z on end, ignore does not

Samples

See Form.Test.Simple and other forms in Form.Test package for samples. To generate test data execute: do ##class(Form.Util.Init).populateTestForms() To remove test forms permanently from your local repository

  1. Enter Form\Test directory from git bash
  2. git update-index --assume-unchanged $(git ls-files | tr '\n' ' ')
  3. Delete Form\Test directory

Object creation

For Form.Test.Simple.

POST http://localhost:57772/forms/form/object/Form.Test.Simple Headers must contain Content-Type and (probably) authorization

Content-Type: application/json
Authorization: Basic Base64String

Body:

{
        "_class":"Form.Test.Simple",
        "text":3
}

Object update

For Form.TestForm.

PUT http://localhost:57772/forms/form/object/Form.Test.Simple

Body:

{
        "_class":"Form.Test.Simple",
        "_id":3,
        "text":4444
}

restforms's People

Contributors

dmitry-zasypkin avatar eduard93 avatar evshvarov avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

restforms's Issues

Wrong "date" processing

If a class has a property with the reserved keyword, request results in an error
Request:
objects/spg.model.slot.Hospitalization/all?orderby=date

Response:
2017-02-12 13 51 40

If we try sql query with: ORDER BY "date" - works fine!

SQL 490 symbols limit

Generated SQL should use property reference if method getObjectDisplayName is undefined

Import of Form162.xml for release 1.5 gives a compilation error in Studio

Importing the Form162.xml file from the 1.5 release into a clean 2017.2 namespace gives a compilation error. At first I assumed it was because the new Form.Settings class had been omitted from the export. But that's not the case. It seems that Caché is getting confused when doing the compile the first time:

Load started on 11/09/2017 12:30:21
Loading file C:\s\RESTForms\sources\1.5-05Oct2017.xml as xml
Imported class: Form.Adaptor
Imported class: Form.Field
Imported class: Form.File
Imported class: Form.Generators
Imported routine: Form.INC
Imported class: Form.Info
Imported class: Form.JSON.OBJ
Imported class: Form.JSON.SQL
Imported package information: Form
Imported class: Form.Property
Imported class: Form.REST.Abstract
Imported class: Form.REST.Field
Imported class: Form.REST.File
Imported class: Form.REST.Form
Imported class: Form.REST.Main
Imported class: Form.REST.Object
Imported class: Form.REST.Objects
Imported class: Form.Security
Imported class: Form.Settings
Imported class: Form.Test.Address
Imported class: Form.Test.Company
Imported class: Form.Test.Person
Imported class: Form.Test.Simple
Imported class: Form.Util.Converter
Imported class: Form.Util.Init
Imported class: Form.Util.Translate
Imported project: Form.prj
Load finished successfully.

Compilation started on 11/09/2017 12:30:22 with qualifiers 'ckd'
Compiling 24 classes, using 4 worker jobs
Compiling class Form.Info
Compiling class Form.Field
Compiling class Form.Generators
Compiling class Form.Property
Compiling class Form.REST.Abstract
Compiling class Form.Security
Compiling class Form.Settings
Compiling class Form.Test.Address
Compiling class Form.Util.Converter
Compiling class Form.Util.Init
Compiling class Form.Util.Translate
Compiling class Form.File
Compiling class Form.JSON.OBJ
ERROR #5002: Cache error: <CLASS DOES NOT EXIST>SetVisited+1^Form.JSON.OBJ.G1 *Form.Settings
  > ERROR #5490: Error running generator for method 'SetVisited:Form.JSON.OBJ' 
ERROR: Form.JSON.OBJ.G1.int(SetVisited+1) : <CLASS DOES NOT EXIST> :  set code = ##class(Form.Settings).getSetting("visited")
ERROR: Form.JSON.OBJ.cls(SetVisited) of generated code
    > ERROR #5030: An error occurred while compiling class 'Form.JSON.OBJ'
Compiling class Form.JSON.SQL
Compiling class Form.REST.Main
Compiling class Form.REST.Form
Compiling class Form.REST.Field
Compiling class Form.REST.File
Compiling class Form.REST.Objects
Compiling class Form.REST.Object
Compiling table Form.File
Compiling routine Form.Generators.1
Compiling routine Form.Info.1
Compiling routine Form.Property.1
Compiling routine Form.REST.Abstract.1
Compiling routine Form.Security.1
Compiling routine Form.Settings.1
Compiling routine Form.Test.Address.1
Compiling routine Form.Util.Converter.1
Compiling routine Form.Util.Init.1
Compiling routine Form.Util.Translate.1
Compiling routine Form.JSON.SQL.1
Compiling routine Form.JSON.OBJ.1
Compiling routine Form.File.1
Compiling routine Form.REST.Form.1
Compiling routine Form.REST.Field.1
Compiling routine Form.REST.Main.1
Compiling routine Form.REST.Object.1
Compiling routine Form.REST.File.1
Compiling routine Form.REST.Objects.1
Compiling class Form.Adaptor
Compiling class Form.Test.Simple
Compiling class Form.Test.Company
Compiling class Form.Test.Person
Compiling table Form_Test.Company
Compiling table Form_Test.Person
Compiling table Form_Test.Simple
Compiling routine Form.Adaptor.1
Compiling routine Form.Test.Company.1
Compiling routine Form.Test.Simple.1
Compiling routine Form.Test.Person.1
Skipping include files generation
Detected 1 errors during compilation in 2.384s.

If I immediately recompile the Form package it goes through cleanly:

Compilation started on 11/09/2017 12:33:24 with qualifiers 'ck'
Compiling 24 classes, using 4 worker jobs
Compiling class Form.Field
Compiling class Form.Info
Compiling class Form.Generators
Compiling class Form.Property
Compiling class Form.REST.Abstract
Compiling class Form.Security
Compiling class Form.Settings
Compiling class Form.Test.Address
Compiling class Form.Util.Converter
Compiling class Form.Util.Init
Compiling class Form.Util.Translate
Compiling class Form.File
Compiling class Form.JSON.OBJ
Compiling class Form.JSON.SQL
Compiling class Form.REST.Field
Compiling class Form.REST.Main
Compiling class Form.REST.File
Compiling class Form.REST.Form
Compiling class Form.REST.Object
Compiling class Form.REST.Objects
Compiling table Form.File
Compiling routine Form.Info.1
Compiling routine Form.Generators.1
Compiling routine Form.Property.1
Compiling routine Form.REST.Abstract.1
Compiling routine Form.Security.1
Compiling routine Form.Settings.1
Compiling routine Form.Test.Address.1
Compiling routine Form.Util.Converter.1
Compiling routine Form.Util.Init.1
Compiling routine Form.Util.Translate.1
Compiling routine Form.JSON.SQL.1
Compiling routine Form.JSON.OBJ.1
Compiling routine Form.File.1
Compiling routine Form.REST.Field.1
Compiling routine Form.REST.Main.1
Compiling routine Form.REST.File.1
Compiling routine Form.REST.Form.1
Compiling routine Form.REST.Object.1
Compiling routine Form.REST.Objects.1
Compiling class Form.Adaptor
Compiling class Form.Test.Simple
Compiling class Form.Test.Company
Compiling class Form.Test.Person
Compiling table Form_Test.Simple
Compiling table Form_Test.Company
Compiling table Form_Test.Person
Compiling routine Form.Adaptor.1
Compiling routine Form.Test.Company.1
Compiling routine Form.Test.Simple.1
Compiling routine Form.Test.Person.1
Skipping include files generation
Compilation finished successfully in 2.362s.

Add Caché Localization support

Compile Displayname as $$$Text to let it be stored as localization resource.
Domain - RESTFORMS
Language - en
In future the language can be a RESTForms parameter to the class

Return all metadata

In the following format:

{ 
formclass: { metadata object },
formclass2: { metadata object}
}

Sample result:

{
   "Form.Test.Person":{
      "name":"Тестовая форма: человек",
      "class":"Form.Test.Person",
      "displayProperty":"name",
      "objpermissions":"CRUD",
      "fields":[
         {
            "name":"name",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Имя",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"gender",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Пол",
            "valueList":[
               "",
               "1",
               "2"
            ],
            "displayList":[
               "",
               "М",
               "Ж"
            ],
            "required":0,
            "category":"datatype"
         },
         {
            "name":"dob",
            "type":"%Library.Date",
            "collection":"",
            "displayName":"Дата рождения",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"аge",
            "type":"%Library.Integer",
            "collection":"",
            "displayName":"Возраст",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"company",
            "type":"Form.Test.Company",
            "collection":"",
            "displayName":"Компания",
            "required":0,
            "category":"form"
         },
         {
            "name":"relative",
            "type":"Form.Test.Person",
            "collection":"",
            "displayName":"Родственник",
            "required":0,
            "category":"persistent"
         },
         {
            "name":"Home",
            "type":"Form.Test.Address",
            "collection":"",
            "displayName":"Дом",
            "required":0,
            "category":"serial"
         }
      ]
   },
   "Form.Test.Company":{
      "name":"Тестовая форма: компания",
      "class":"Form.Test.Company",
      "displayProperty":"name",
      "objpermissions":"CRUD",
      "fields":[
         {
            "name":"name",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Название",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"employees",
            "type":"Form.Test.Person",
            "collection":"array",
            "displayName":"Работники",
            "required":0,
            "category":"persistent"
         }
      ]
   },
   "Form.Test.Simple":{
      "name":"Тестовая форма",
      "class":"Form.Test.Simple",
      "displayProperty":"displayName",
      "objpermissions":"CRUD",
      "fields":[
         {
            "name":"displayName",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Имя",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"text",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Текст",
            "required":0,
            "category":"datatype"
         },
         {
            "name":"gender",
            "type":"%Library.String",
            "collection":"",
            "displayName":"Пол",
            "valueList":[
               "",
               "1",
               "2"
            ],
            "displayList":[
               "",
               "М",
               "Ж"
            ],
            "required":0,
            "category":"datatype"
         }
      ]
   }
}

Сортировка списка объектов по выбранному св-ву

Добавить в Adaptor параметр, в котором будет указываться свойство (или даже список свойств), по которому необходимо сортировать список объектов.

Например, для справочника классов МКБ нужна сортировка по id, а не по коду (римские цифры) и не по названию класса.

Add settings interface

Settings are stored in global.
Add Form.Settings class with SetSetting/GetSetting methods

Remove system methods

What to do?

https://gist.github.com/bspead/bf23a28029e8d389ac39a3a4af3342bd
https://community.intersystems.com/post/writing-forward-compatible-json-20161

IMPORTANT DISCLAIMER: These macros are being provided as examples and are in no way supported by InterSystems (and they will not be part of the product). Also, after all instances of an application are upgraded to 2016.2 or higher the macros should be removed – they are not intended for permanent inclusion in an application’s code base.

Унификация представления данных клиенту

Цели:

  • унификация объектного и SQL доступа
  • предоставление данных в формате, не зависимом от локали
  • предоставление данных в формате, понятном js

Основные проблемы:

  • как передавать даты
  • как передавать время
  • как передавать timestamp
  • как передавать числа

2016.3 info
json dates

Update record doesn't work

When I am using this code and i am trying to update a record it doesn't work... Create, Read and Delete seem to work well... see attached screencast
screencast-172 17 19 81-57772-2019 01 09-10-20-03

doesnotcontain работает не очевидно, либо возможно не работает.

(✔) blablaurl/all?filter=manager+contains+DEV все хорошо работает
(✘) blablaurl/all?filter=manager+doesnotcontain+DEV возвращает следующую ошибку:

error : 
"ERROR #5521: SQLError: SQLCODE=-3 %msg= Closing quote (') missing^SELECT *, %CLASSNAME as _class, purchase->submissionCloseDateTime as submissionCloseDateTime FROM eis_model_contract.Contract WHERE manager'['DEV' ORDER BY createDateTime DESC"

а вообще так можно делать? "'[" у меня и в SQL ломается

Compilation Error in Caché 2017.2

Possibly #22 related.

While compiling classes from master branch, I get this-like error messages:

ОШИБКА #5373: Класс '%Library.Object', используемый 'Form.Generators:onGenerateMetadata:FormalSpec', не существует

...and so on. Seem like deprecated %Object wasn't replaced to %DynamicObject.

Сортировка списка объектов по выбранному св-ву

Хорошо бы добавить в Adaptor параметр, в котором будет указываться свойство (или даже список свойств), по которому необходимо сортировать список объектов.

Например, для справочника классов МКБ нужна сортировка по id, а не по коду (римские цифры) и не по названию класса.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.