BaaS with Kinvey and Delphi 10.1 Berlin

In this article I will show you how to connect yourdesktop and mobile applications to a mobile backend as a service (mBaaS) with Delphi 10.1 Berlin. I normally use Parse.com as a backend but as they announce that they will close their mBaaS service I will use Kinvey instead.

If you are interested in Parse.com you can read my previous articles about creating your own self-hosted Parse server and deploying a Parse server to Herokuwhich achieves similar result to what I want to explain you today (basically having your data hosted anywhere in the cloud either using Kinvey as an mBaaSor Parse + Heroku as a PaaS).

There are plenty of articles online about these topics and I just want to give you my input and how I dealt with some of the challenges I faced during development.

Join Kinvey and create your App environment

First step is to join Kinvey and create your application environment. Kinvey offers a Free plan for developers that it is ideal to test your applications. It includes the core mBaaS features and 1GB of data storage. Once you move your solution into production you can switch over one of the other plans available.

Once you are in the console management, press "New App" and enter the name of your backend:

Now you should see your enviromnent created:

Click on the Development label and the dashboard will be shown:

At this moment in time, you should know what data you are going to store. In this example I have created a simple collection that includes several fields for a sample application that I‘m building and that the source code can be found here:

Here is my collection of values:

*Note that if you POST data to a non-existing collection, this will be created automatically.

Handling collections

Now it‘s time to start using the collection and querying/adding data via Http REST. For this task you will have to identify the required headers that are needed for your GET/POST requests. You can see one example here for Parse.

Kinvey follows a different approach than Parse in terms of security. Kinvey offers basic and session authentiation. Basic authentication uses the HTTP header "Authorization" with the components "Basic" andBase64Encode(AppId:MasterSecret). Session authentication sends a login request to collct an auth token from Kinvey backend and then this token is used in subsequent REST requests.

I will focus on Basic authentication as Session authentication is as simple but with more steps.

The first example is by using REST via IdHttp so you can see how GET/POST are handled manually and the second example is just by using the Kinvey provider component available with our Delphi 10.1 Berlin that will make our life easier.

Here it‘s my Win64 example that uses Kinvey BaaS:

Add action, adds data into the collection and reload just brings the data back from the cloud and displays it in a listview component.

Here is the code behind it:
Add item:

  // Copyright (c) 2016, Jordi Corbilla
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  // - Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  // - Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation
  // and/or other materials provided with the distribution.
  // - Neither the name of this library nor the names of its contributors may be
  // used to endorse or promote products derived from this software without
  // specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
   
  function TKinveyRest.Add(jsonString: string) : boolean;
  var
  IdHTTP: TIdHTTP;
  IdIOHandler: TIdSSLIOHandlerSocketOpenSSL;
  response : string;
  JsonToSend: TStringStream;
  encodedHeader : string;
  begin
  JsonToSend := TStringStream.Create(jsonString);
  try
  IdIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  IdIOHandler.ReadTimeout := IdTimeoutInfinite;
  IdIOHandler.ConnectTimeout := IdTimeoutInfinite;
  IdHTTP := TIdHTTP.Create(nil);
  try
  IdHTTP.IOHandler := IdIOHandler;
  IdHTTP.Request.Connection := ‘Keep-Alive‘;
  IdIOHandler.SSLOptions.Method := sslvSSLv23;
  IdHTTP.Request.CustomHeaders.Clear;
  encodedHeader := TIdEncoderMIME.EncodeString(FOptions.AppId + ‘:‘ + FOptions.MasterSecret);
  IdHTTP.Request.CustomHeaders.Values[‘Authorization‘] := ‘Basic ‘ + encodedHeader;
  IdHTTP.Request.CustomHeaders.Values[‘X-Kinvey-API-Version‘] := ‘3‘;
  IdHTTP.Request.ContentType := ‘application/json‘;
  response := IdHTTP.Post(‘https://baas.kinvey.com/appdata/‘+FOptions.AppId+‘/‘+FOptions.Collection+‘/‘, JsonToSend);
  response := response.Replace(AnsiChar(#10), ‘‘);
  result := (response.Contains(‘creator‘));
  finally
  IdHTTP.Free;
  end;
  finally
  IdIOHandler.Free;
  JsonToSend.Free;
  end;
  end;

view rawKinveyAdd.pas hosted with ? by GitHub

Load data:

  // Copyright (c) 2016, Jordi Corbilla
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  // - Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  // - Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation
  // and/or other materials provided with the distribution.
  // - Neither the name of this library nor the names of its contributors may be
  // used to endorse or promote products derived from this software without
  // specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
   
  function TKinveyRest.GetCollection: string;
  var
  IdHTTP: TIdHTTP;
  IdIOHandler: TIdSSLIOHandlerSocketOpenSSL;
  response : string;
  encodedHeader : string;
  begin
  try
  IdIOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(nil);
  IdIOHandler.ReadTimeout := IdTimeoutInfinite;
  IdIOHandler.ConnectTimeout := IdTimeoutInfinite;
  IdHTTP := TIdHTTP.Create(nil);
  try
  IdHTTP.IOHandler := IdIOHandler;
  IdHTTP.Request.Connection := ‘Keep-Alive‘;
  IdIOHandler.SSLOptions.Method := sslvSSLv23;
  IdHTTP.Request.CustomHeaders.Clear;
  encodedHeader := TIdEncoderMIME.EncodeString(FOptions.AppId + ‘:‘ + FOptions.MasterSecret);
  IdHTTP.Request.CustomHeaders.Values[‘Authorization‘] := ‘Basic ‘ + encodedHeader;
  IdHTTP.Request.CustomHeaders.Values[‘X-Kinvey-API-Version‘] := ‘3‘;
  IdHTTP.Request.ContentType := ‘application/json‘;
  response := IdHTTP.Get(‘https://baas.kinvey.com/appdata/‘+FOptions.AppId+‘/‘+FOptions.Collection+‘/‘);
  result := response;
  finally
  IdHTTP.Free;
  end;
  finally
  IdIOHandler.Free;
  end;
  end;

view rawKinveyLoad.pas hosted with ? by GitHub

As you can see, each method uses a POST/GET command to baas.kinvey url with some arguments, headers and options. I find this way really useful as you can clearly see what‘s going on and easily map what you could do via curl:

  #Example posting to Kinvey via curl
  >curl -H ‘Content-Type: application/json‘ --user APPKEY:MASTERSECRET -X PUT -d ‘{"user":"user","password":"password","url","www.google.co.uk"}‘ https://baas.kinvey.com/appdata/APPKEY/Websites
   
  #Example reading the content of the collection
  >curl --user APPKEY:MASTERSECRET -X GET https://baas.kinvey.com/appdata/APPKEY/Websites/ -G --data-urlencode ‘order={"user"}‘

view rawKinveyCurlExample.cmd hosted with ? by GitHub

If you want to run this example successfully you‘ll need to include libeay32.dll and ssleay32.dll from OpenSSL.

You can test this app and its mobile companion app using the source codehere.

Using Kinvey Provider component
Delphi 10.1 Berlin has a KinveyProvider component that we can use directly without having to worry about the request details. You‘ll see below that to do the same as the code sample above we will need just few lines of code:

The KinveyProvider needs the parameters:

  • AppKey
  • AppSecret
  • MasterSecret

Get those from the Kinvey dashboard and off you go.

Then connect the BackEndStorage component to the KinveyProvider component.

Now, here is the code to Add items to the collection and to load the collection via components:
Load Data:

  // Copyright (c) 2016, Jordi Corbilla
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  // - Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  // - Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation
  // and/or other materials provided with the distribution.
  // - Neither the name of this library nor the names of its contributors may be
  // used to endorse or promote products derived from this software without
  // specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
   
  function TForm2.GetCollection() : TList<TUrls>;
  var
  list: TList<TUrls>;
  url: TUrls;
  begin
  try
  FBackendList := CreateUrlsList(BackendStorage1.Provider.ProviderID, BackendStorage1.Storage);
  list := TList<TUrls>.Create;
  try
  for url in FBackendList do
  list.Add(url);
  except
  list.Free;
  raise;
  end;
  finally
  result := list;
  end;
  end;
   
  function TForm2.CreateUrlsList(const AProviderID: string; const AStorage: TBackendStorageApi): TBackendObjectList<TUrls>;
  var
  LQuery: TArray<string>;
  LContactList: TBackendObjectList<TUrls>;
  begin
  LContactList := TBackendObjectList<TUrls>.Create;
  try
  LQuery := TArray<string>.Create(Format(‘order=%s‘, [‘user‘]));
  AStorage.QueryObjects<TUrls>(‘websites‘, LQuery, LContactList);
  except
  LContactList.Free;
  raise;
  end;
  Result := LContactList;
  end;

view rawKinveyComponentLoad.pas hosted with ? by GitHub

Add Item:

  // Copyright (c) 2016, Jordi Corbilla
  // All rights reserved.
  //
  // Redistribution and use in source and binary forms, with or without
  // modification, are permitted provided that the following conditions are met:
  //
  // - Redistributions of source code must retain the above copyright notice,
  // this list of conditions and the following disclaimer.
  // - Redistributions in binary form must reproduce the above copyright notice,
  // this list of conditions and the following disclaimer in the documentation
  // and/or other materials provided with the distribution.
  // - Neither the name of this library nor the names of its contributors may be
  // used to endorse or promote products derived from this software without
  // specific prior written permission.
  //
  // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
  // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  // POSSIBILITY OF SUCH DAMAGE.
   
  procedure TForm2.btnAddClick(Sender: TObject);
  var
  url : TUrls;
  entity: TBackendEntityValue;
  begin
  url := TURls.Create(edit1.Text, edit2.Text, edit3.Text);
  BackendStorage1.Storage.CreateObject<TUrls>(‘websites‘, url, entity);
  end;

view rawKinveyComponentAdd.pas hosted with ? by GitHub

As you can see now it‘s way simpler.

And here my android app up and running:

Now I have a Win64 app and an Android app that share the same back end usingKinvey BaaS.

And the data in Kinvey:

Although this article it‘s quite long I‘m sure you will find it quite interesting if you still haven‘t played with these components and the cloud.

Note that this BackEnd service will cease to exist shortly (as the appkey is hardcoded in the android app and the source code is available).

Do not hesitate to contact me if you have any questions.

http://www.delphifeeds.com/go/s/134494

时间: 2024-11-08 19:13:09

BaaS with Kinvey and Delphi 10.1 Berlin的相关文章

Where is the ActiveX Project Type for Delphi 10.1 Berlin

n 10.1 Berlin the ActiveX project types are missing from the New Items Window under Delphi. They are there for C++Builder, but not for Delphi. This only happens if you use the shiney new Feature Installer that was introduced with 10.1 Berlin. So if y

Delphi 10.1 Berlin Starter Edition

Delphi 10.1 Berlin Starter Edition Embarcadero? Delphi 10.1 Berlin Starter is a great way to get started building high-performance Delphi apps for Windows. Delphi Starter includes a streamlined IDE, code editor, integrated debugger, two-way visual de

Delphi 10.1 Berlin 官方未列之修正

Delphi 10.1 Berlin 官方未列之修正: 修正 iOS App 设定为全屏后,无法使用 Zoom, Pan, LongTap 等手势. 修正 ListView 移动平台 (iOS, Android) 与 Windows 事件先后顺序不相同(现在统一了):iOS, Android: 先进 OnMouseUp 後进 OnChangeWindows: 先进 OnChange 後进 OnMouseUp 修正 Android Intel CPU(如:ASUS ZenPhone)上方状态栏重叠

delphi 10.1 Berlin 中使用自带的 Base64 编码

delphi 10.1 berlin版本中,有好几个 base64 编码的单元可以使用,例如 Indy, MessageDigest_5,还有 CnBase64,我现在使用自带的 System.NetEncoding. var params: string; Digest: TBytes; Base64: TBase64Encoding; begin Base64 := TBase64Encoding.Create; params := Base64.EncodeBytesToString(Di

TNetHttpClient支持异步访问(Delphi 10.1 Berlin,红鱼儿的博客)

Delphi 10.1进一步改进自Delphi 10带来的Http访问控件TNetHttpClient,支持异步访问,同时增加ConnectionTimeout及ResponseTimeout两个超时属性.你也许会问,这有什么?其他的语言早就有了,而我想到的确实别看这些常规的功能增加,他可以跨平台的啊,熟知Delphi跨平台的开发者一说就明白,这是跨win,osx,android,ios的,今年底还要linux.我又说多了,好象劝你也来用delphi似的.我们看一下如何使用异步处理Http请求.

Delphi 10.1 Berlin 与 Delphi 10 Seattle 共存

以下安装环境是win7 64位 1. 安装Delphi10.1 Berlin 版本. 2.修改C:\Program Files (x86)\Embarcadero\Studio\18.0\cglm.ini文件 [Embarcadero License Management]RootDir=${MODULE_DIR}\..LicenseDir=${ROOTDIR}\LicenseInfoDir=${COMMON_APPDATA}\Embarcadero\18\.licensesSlipDir=${

打开Delphi 10.1 berlin提示脚本错误的解决方法

HKEY_CURRENT_USER\SOFTWARE\Embarcadero\BDS\18.0\Known IDE Packages $(BDS)\Bin\CommunityToolbar240.bpl Embarcadero Community Toolbar Package 修改为_Embarcadero Community Toolbar Package

Delphi 10.2 JSON与对象/结构体序列化性能提高100多倍

今天在盒子闲逛,无意中看到有人说XE7自带的Json对象序列化很慢,帖子在这里:http://bbs.2ccc.com/topic.asp?topicid=464378;经过测试的确如此.     但是 D10.2后,自带的 Json 做了优化,性能大大的提高了100多倍. 和其他json库对比了序列化和反序列化性能,JsonDataObjects 性能最好,但是只支持简单的对象,不支持结构体,QJson 则不支持动态数组,不支持 Attributes (RTTI),比如需要过滤某个字段,自带和

Delphi 10.1.2 berlin开发跨平台APP的几点经验

1.ios不允许app有退出功能,所以不能调用Application.Terminate. 2.info.plist文件的自定义:info.plist文件是由info.plist.TemplateiOS.xml生成的,如果需要定制info.plist内容,则修改info.plist.TemplateiOS.xml即可 3.界面文字的大小建议使用13,统一android与ios的显示,我在android下用12,生成ios app时,发现小些. 4.使用TFrame来做界面,感觉效率比Form要好