Shubham Ankit

Shubham Ankit

1561606463

How to Set Up a REST Service or a Web Application in Django

A tutorial for beginners on how to get started using Python and Django, and then develop a simple REST service using them…

Introduction to Django and REST

Django is a very versatile framework, primarily used for developing web applications, but it is also widely used in creating mobile app backends and REST APIs, among other things. Here we will take a quick look at how to make these things possible using Django.

As you all probably know, REST stands for “Representational State Transfer.” Basically, what happens is that a user (or some software agent on one end) provides some input (or performs some activity) and the result of those inputs (or activities) are sent to the server side using a protocol that allows a request to be sent to the server (in most cases a HTTP protocol is used, but it doesn’t need to be HTTP, as long as it can support a request/response scheme). The server, on receiving the request, makes appropriate changes to the state of the system (hence we call it “State Transfer”).

A Brief Discussion on How to Create a Django Project

Django runs on HTTP protocol, and hence it is very handy in creating a REST API or a RESTful application. It allows the user to provide inputs on a web interface (or any interface that is capable of sending a HTTP request object to the Django application). In our examples in this document, we will be considering web application interfaces, but you can easily stretch them to a mobile app or any other app that can send a similar HTTP request.

In order to understand how to do these things, we need to know a bit of Django here. This is my first post in a series of 5 posts on the same topic, so, in this document, I will acquaint you with certain Django files that are of the utmost importance, along with the basic structure of a Django app (please note that ‘Django’ is pronounced as ‘jango’, NOT D-jango. The first character, ‘D,’ is silent.).

A ‘Django project’ is composed of a number of ‘Django applications’ that are stitched together with some logic. The first thing that you do when creating a Django project is to install Django in your Python library. This is usually done by running the command pip install Django==. You may skip the version number part, in which case the latest version of Django that can be handled by your OS and your Python distro installed on your system will be installed. Fair enough.

Once the installation is successfully complete, you will find a file named “django-admin” in the path of your computer. (run which django-admin to see where it exists; on my system it is in /usr/bin/django-admin). To create a project, you need to execute the following command in a directory of your choice. Preferably create a new directory, cd into it and run the following command:

#> django-admin  startproject 

Your project name has be to provided to create the Django project. For example, let us assume I am creating a project named “testyard.” In order to create my project, I need to execute the following command:

#> django-admin startproject testyard

The above command creates the following directory structure in the directory where you executed the above mentioned command.

testyard/
    manage.py
    testyard/
        __init__.py
        settings.py
        urls.py
        wsgi.py

A Discussion on the Files Created Above

The first file, manage.py, is very important. This is the file that will eventually assist you in creating applications, running the Django test web server, running Django management tasks (not covered in this document, but we will take look at it in a later article), and a host of other activities. The __init__.py file in the next level ensures that we will be working in an object-oriented environment. Next comes the two most important files: settings.py and urls.py. We will discuss the settings.py file first and urls.py next.

  • settings.py: This file contains the settings for the Django applications to work. Some of the more important config params in this file are the database connection parameters (username, password, database name, DB host, port, Engine, etc.), static file locations, Template Loaders, Middleware classes (we will be dicussing this in another article, but just keep in mind that these are the programs that interact with the request object before they reach the “view” functions, so they are capable of changing the request before it can be processed), installed apps, root urlconf (we will discuss this in this article later), etc. You are also free to write your own application specific settings file in the same location. However, you need to give it a different name and then import settings.py into it. There are a load of other parameters in settings.py and I would request you to go through the settings.py GitHub repo and figure out the parameters.
  • urls.py: This file contains the map of the path requested by a client (browser or a bot) to the specific view function that needs to be called when the given path is requested by an HTTP request. You will find a sample of such a urls.py file in this GitHub repo. This file is also known as the urlconf.

The file named wsgi.py exists to allow the applications you are creating to run on uWSGI and Nginx (the production environment stuff). We will be taking a look at this file later in this article.

Once these files have been created, you can start creating applications inside the project. But first, you need to figure out if the previous procedure is working fine with a server. So for that purpose, you need to run the application’s development server.

To do this, you need to run the following command on the command prompt. Note that in order to run this, you need to be in the same directory where “manage.py” exists.

#>python manage.py runserver 0.0.0.0:8080

This command will start the development server. Now, you should be able to go to a browser, type in localhost:8080/login/, and you should be able to see the login screen if urls.py has an entry for that URL path. Alternatively, you may just type localhost:8080/ to see if your Django server is running.

So that makes you capable enough to start creating a REST API using Python/Django. In the subsequent sections we will demonstrate how to write code to create the REST API.

View Files in Django

The views.py file in Django follows a variation of the the MVC design pattern, and it is normally referred to as the MVT pattern. The ‘M’ stands for the model (the DB schema), V stands for views.py, which in an MVC framework is the controller part, while the ‘T’ stands for templates, which in an MVC framework would be the view component.

Since we will be looking at the REST API first, we will concentrate on the views.py file. First, have a look at the handlers.py file at the following GitHub repo. In this program, the code that is to be in views.py has been put into handlers.py, but for all intents and purposes, they work in the same manner. You may consider the code in handlers.py to be that of views.py in this example (actually, this was some code I wrote long back when I was just starting to dabbling in Django; hence I made something to see if Django is flexible enough, and found that it sure was flexible).

The Structure and Behavior of Django

The views.py file will contain one or more functions (note that it may also contain classes, and we will take a look at classes in views.py in another post), and the functions will contain only one argument: a “request.” The “request” is basically an instance of the HttpRequest class (defined by Django). All view functions in a Django app consume an instance of this HttpRequest class and return an instance of the HttpResponse class.

Why do we need to have multiple functions in the views.py file? This is because you might want to serve multiple pages or responses, each of which has a different URL path. For example, you might want to serve a login page, a registration page, an activity to check the login credentials of the user who is trying to login into your app, and a dashboard page. Each of these pages will have a different URL path, say, http://mywebsite.com/login for login page, http://mywebsite.com/registration** **for registration page, and so on. So each of these URLs will need a separate function to handle the request. Hence, we need one function for each of these actions in the views.py file.

How do we associate each of the activities mentioned above with a specific views.py function? This is where the urls.py file comes into play. urls.py has a map of each URL path to a specific function in views.py of a particular Django app (remember we mentioned in the begining that a Django project is composed of one or more Django apps. We will get to the apps part in a moment). A urls.py looks something like the following:

urlpatterns = patterns('',
(r'^time/
, current_datetime),
(r'^savewhatyoulookedat/login/
, userLogin),
(r'^savewhatyoulookedat/register/
, userRegister),
(r'^savewhatyoulookedat/
, saveURL),
(r'^savewhatyoulookedat/logout/
, userLogout),
(r'^savewhatyoulookedat/downloadPlugin/
, firefoxPluginDownload),
(r'^savewhatyoulookedat/managedata/
, manageData),
(r'^savewhatyoulookedat/commandHandler/
, executeCommand),
(r'^savewhatyoulookedat/showimage/
, showImage),
(r'^savewhatyoulookedat/search/
, searchURL),
# (r'^admin/doc/', include('django.contrib.admindocs.urls')),
# Uncomment the another line to enable the authority:
# (r'^admin/', include(admin.site.urls)),
)

Basically, as you can see, the mapping is actually between a regular expression that should match the URL path and a function in the views.py file. As you create more activity handlers in your views.pyfile, you keep adding an entry for each of them in the urls.py file. For a Django project with multiple applications, the urls.py file might also look like the following:

urlpatterns += patterns('',
url(r'^%s
%mysettings.REGISTER_URL, 'skillstest.Auth.views.register', name='newuser'),
url(r'^%s
%mysettings.DASHBOARD_URL, 'skillstest.views.dashboard', name='dashboard'),
url("%s$"%mysettings.LOGIN_URL, 'skillstest.Auth.views.login', name='login'),
url(r'%s
%mysettings.MANAGE_TEST_URL, 'skillstest.Tests.views.manage', name='managetests'),
url(r'%s
%mysettings.CREATE_TEST_URL, 'skillstest.Tests.views.create', name='createtests'),
url(r'%s
%mysettings.EDIT_TEST_URL, 'skillstest.Tests.views.edit', name='edittests'),
url(r'%s
%mysettings.ABOUTUS_URL, 'skillstest.views.aboutus', name='aboutus'),
url(r'%s
%mysettings.HELP_URL, 'skillstest.views.helpndocs', name='helpndocs'), url(r'%s%mysettings.CAREER_URL, 'skillstest.views.careers', name='careers'),
... ... ...

‘Auth’ and ‘Tests’ are the names of the applications in the “skillstest” project. Don’t worry about the variables in uppercases — they are defined elsewhere and are of no consequence to our example here.

So, now let us see how to create an application inside a project. We do that by executing the following command:

**python manage.py startapp **

For example, if our app name is “Letsplay”, then we would run

python manage.py startapp Letsplay

The above command creates a directory structure like the following:

Letsplay/
__init__.py
admin.py
apps.py
migrations/
__init__.py
models.py
tests.py
views.py

In the above structure, we will focus mostly on the views.py and the models.py files. However, we will also touch upon the others first.

The admin.py file is required if you want to customize your admin panel in Django. Normally, if you try to access the URL http://localhost:8080/admin, you would see an admin panel. This will display you all the models you have (we will discuss models in just a bit), the config settings of your django project (in read only mode, of course), etc.

The apps.py file allows the creator of the Django app to put in some application specific parameters. Each app in a Django project has its own apps.py file.

The tests.py file allows the app creator to write tests for the app. This file needs to conform to a certain structure. It needs to define a class for a specific test case. This class needs to have a method named setUp, and then it should have the tests defined as methods in the class itself. Unless you are a Django purist, you won’t use this file to define your tests. Normally, in the real life scenarios, we have an application created using Django, another component created using some other technology, and several other components fitted together to work as a service. In such cases, we need to write tests to check the functionality of the entire scheme of things rather than just the Django part. Hence, it is almost customary to create tests as a different suite using Python or some other language like Perl or Ruby (or whatever the tester prefers).

By and large, any application you write (in Python using Django or any other language and framework), you eventually end up interacting with a database somewhere down the line. All Django apps also tend to do the same. This is where the models.py file steps in. The models.py file basically provides you with an ORM (Object-Relational-Mapping) scheme in the Django app. Hence for every table in your prefered database, you have a class defined for it in the models.py file. It looks something like this:

from django.db import models
import os, sys, re, time, datetime
import inspect
"""
'Topic' is basically category or domain.
"""
class Topic(models.Model):
	topicname = models.CharField(max_length=150)
	user = models.ForeignKey(User, null=False)
	createdate = models.DateField(auto_now=True)
	isactive = models.BooleanField(default=True)
class Meta:
verbose_name = "Topics Table"
db_table = 'Tests_topic'
def __unicode__(self):
return "%s"%(self.topicname)
class Subtopic(models.Model):
	subtopicname = models.CharField(max_length=150)
	subtopicshortname = models.CharField(max_length=50)
	topic = models.ForeignKey(Topic, blank=False, null=False)
	createdate = models.DateField(auto_now=True)
	isactive = models.BooleanField(default=True)
class Meta:
	verbose_name = "Subtopics Table"
	db_table = 'Tests_subtopic' # Name of the table in the database
def __unicode__(self):
return "%s (child of %s)"%(self.subtopicname, self.topic.topicname)
class Session(models.Model):
	sessioncode = models.CharField(max_length=50, unique=True)
	status = models.BooleanField(default=True) # Will be 'True' as soon as the user logs in, and will be 'False' when user logs out.
# The 'status' will automatically be set to 'False' after a predefined period. So users will need to login again after that period.
# The predefined value will be set in the settings file skills_settings.py. (skills_settings.SESSION_EXPIRY_LIMIT)
	user = models.ForeignKey(User, null=False, blank=False, db_column='userid_id')
	starttime = models.DateTimeField(auto_now_add=True) # Should be automatically set when the object is created.
	endtime = models.DateTimeField(default=None)
	sourceip = models.GenericIPAddressField(protocol='both', help_text="IP of the client's/user's host")
	istest = models.BooleanField(default=False) # Set it to True during testing the app.
	useragent = models.CharField(max_length=255, default="", help_text="Signature of the browser of the client/user") # Signature of the user-agent to guess the device used by the user.
# This info may later be used for analytics.
class Meta:
	verbose_name = "Session Information Table"
	db_table = 'Auth_session'
def __unicode__(self):
return self.sessioncode
def isauthenticated(self):
if self.status and self.user.active:
return self.user
else:
return None
def save(self, **kwargs):
super(Session, self).save(kwargs)

The attributes in the classes are the fields in the respective tables in the database. The name of the DB table is defined in the “class Meta” of each of the Topic and Subtopic classes with the attribute named db_table. The database associated with these tables is defined in the settings.py file (remember when we discussed settings.py file attributes?). For the datatypes used in the models.py file, you need to look up the Django documentation as there are quite a few data types and relationships and they cannot be dealt with here. In fact, the documentation for them is quite substantial. However, we have used only a few of them above and they are quite self-explanatory.

Actually, Django is quite popular because of two reasons.

  1. It provides the developer with all the boiler plate code, so the coder doesn’t need to write all the boring stuff.
  2. It provides the coder with the ORM, so retrieving or setting a value in a certain row of a specific table in the DB is quite easy. That is the up side of it. There is a down side too. When you use ORM, you do not use SQL statements, and hence if the operation is a little complex, the ORM can become quite inefficient. With SQL statements, you can do some optimization to make the statement run faster, but with ORM, there is no such possiblity. For this reason, Django offers a way out. You can create “raw” SQL statements to query your DB, but this is rarely used by most developers. You should use “raw” SQL statements only when you see that the ORM way of manipulating the DB is distinctively inefficient.

Anyway, let us now move on to the final stages of this document. This happens to be the most important stage in the creation of a REST application. We will now take a look at the views.py file. Please refer to the example code below:

#User login handler
def login(request):
    if request.method == "GET":
    msg = None
if request.META.has_key('QUERY_STRING'):
    msg = request.META.get('QUERY_STRING', '')
if msg is not None and msg != '':
    msg_color = 'FF0000'
msg = skillutils.formatmessage(msg, msg_color)
else :
    msg = ""
#Display login form
curdate = datetime.datetime.now()
tmpl = get_template("authentication/login.html")
c = {
    'curdate': curdate,
    'msg': msg,
    'register_url': skillutils.gethosturl(request) + "/" + mysettings.REGISTER_URL
}
c.update(csrf(request))
cxt = Context(c)
loginhtml = tmpl.render(cxt)
for htmlkey in mysettings.HTML_ENTITIES_CHAR_MAP.keys():
    loginhtml = loginhtml.replace(htmlkey, mysettings.HTML_ENTITIES_CHAR_MAP[htmlkey])
return HttpResponse(loginhtml)
elif request.method == "POST":
    username = request.POST.get('username') or ""
password = request.POST.get('password') or ""
keeploggedin = request.POST.get('keepmeloggedin') or 0
csrfmiddlewaretoken = request.POST.get('csrfmiddlewaretoken', "")
userobj = authenticate(username, password)
if not userobj: #Incorrect password - return user to login screen with an appropriate message.
message = error_msg('1002')
return HttpResponseRedirect(skillutils.gethosturl(request) + "/" + mysettings.LOGIN_URL + "?msg=" + message)
else : #user will be logged in after checking the 'active'
field
if userobj.active:
    sessobj = Session()
clientip = request.META['REMOTE_ADDR']
timestamp = int(time.time()) 
# timestamp will be a 10 digit string.
sesscode = generatesessionid(username, csrfmiddlewaretoken, clientip, timestamp.__str__())
sessobj.sessioncode = sesscode
sessobj.user = userobj
# sessobj.starttime should get populated on its own when we save this session object.
sessobj.endtime = None
sessobj.sourceip = clientip
if userobj.istest: #This session is being performed by a test user, so this must be a test session.
sessobj.istest = True
elif mysettings.TEST_RUN: #This is a test run as mysettings.TEST_RUN is set to True
sessobj.istest = True
else :
    sessobj.istest = False
sessobj.useragent = request.META['HTTP_USER_AGENT']
# Now save the session...
sessobj.save()
#...and redirect to landing page(which happens to be the profile page).
response = HttpResponseRedirect(skillutils.gethosturl(request) + "/" + mysettings.LOGIN_REDIRECT_URL)
response.set_cookie('sessioncode', sesscode)
response.set_cookie('usertype', userobj.usertype)
return response
else :
    message = error_msg('1003')
return HttpResponseRedirect(skillutils.gethosturl(request) + "/" + mysettings.LOGIN_URL + "?msg=" + message)
else :
    message = error_msg('1001')
return HttpResponseRedirect(skillutils.gethosturl(request) + "/" + mysettings.LOGIN_URL + "?msg=" + message)
-- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -
#User registration handler
def register(request):
    privs = Privilege.objects.all()
privileges = {}
for p in privs:
    privileges[p.privname] = p.privdesc
if request.method == "GET": #display the registration form
msg = ''
if request.META.has_key('QUERY_STRING'):
    msg = request.META.get('QUERY_STRING', '')
if msg is not None and msg != '':
    var, msg = msg.split("=")
for hexkey in mysettings.HEXCODE_CHAR_MAP.keys():
    msg = msg.replace(hexkey, mysettings.HEXCODE_CHAR_MAP[hexkey])
msg = "
%s
" % msg
else :
    msg = ""
curdate = datetime.datetime.now()
    (username, password, password2, email, firstname, middlename, lastname, mobilenum) = ("", "", "", "", "", "", "", "")
tmpl = get_template("authentication/newuser.html")# c = {
    'curdate': curdate,
    'msg': msg,
    'login_url': skillutils.gethosturl(request) + "/" + mysettings.LOGIN_URL,
    'register_url': skillutils.gethosturl(request) + "/" + mysettings.REGISTER_URL,
    'privileges': privileges,
    'min_passwd_strength': mysettings.MIN_ALLOWABLE_PASSWD_STRENGTH,
}
c = {
    'curdate': curdate,
    'msg': msg,
    'login_url': skillutils.gethosturl(request) + "/" + mysettings.LOGIN_URL,
    'hosturl': skillutils.gethosturl(request),
    \
    'register_url': skillutils.gethosturl(request) + "/" + mysettings.REGISTER_URL,
    \
    'min_passwd_strength': mysettings.MIN_ALLOWABLE_PASSWD_STRENGTH,
    'username': username,
    'password': password,
    'password2': password2,
    \
    'email': email,
    'firstname': firstname,
    'middlename': middlename,
    'lastname': lastname,
    'mobilenum': mobilenum,
    \
    'availabilityURL': mysettings.availabilityURL,
    'hosturl': skillutils.gethosturl(request),
    'profpicheight': mysettings.PROFILE_PHOTO_HEIGHT,
    'profpicwidth': mysettings.PROFILE_PHOTO_WIDTH
}
c.update(csrf(request))
cxt = Context(c)
registerhtml = tmpl.render(cxt)
for htmlkey in mysettings.HTML_ENTITIES_CHAR_MAP.keys():
    registerhtml = registerhtml.replace(htmlkey, mysettings.HTML_ENTITIES_CHAR_MAP[htmlkey])
return HttpResponse(registerhtml)
elif request.method == "POST": #Process registration form data
username = request.POST['username']
password = request.POST['password']
password2 = request.POST['password2']
email = request.POST['email']
firstname = request.POST['firstname']
middlename = request.POST['middlename']
lastname = request.POST['lastname']
sex = request.POST['sex']
usertype = request.POST['usertype']
mobilenum = request.POST['mobilenum']
profpic = ""
# userprivilege = request.POST['userprivilege']
csrftoken = request.POST['csrfmiddlewaretoken']
message = ""
# Validate the collected data...
if password != password2:
    message = error_msg('1011')
elif mysettings.MULTIPLE_WS_PATTERN.search(username):
    message = error_msg('1012')
elif not mysettings.EMAIL_PATTERN.search(email):
    message = error_msg('1013')
elif mobilenum != ""
and not mysettings.PHONENUM_PATTERN.search(mobilenum):
    message = error_msg('1014')
elif sex not in ('m', 'f', 'u'):
    message = error_msg('1015')
elif usertype not in ('CORP', 'CONS', 'ACAD', 'CERT'):
    message = error_msg('1016')
elif not mysettings.REALNAME_PATTERN.search(firstname) or not mysettings.REALNAME_PATTERN.search(lastname) or not mysettings.REALNAME_PATTERN.search(middlename):
    message = error_msg('1017')
    ....
    ....
return HttpResponse(html)

The above code has two functions, and we will discuss them shortly. But before that, please take a look at the corresponding urls.py file for these two above functions:

urlpatterns = patterns('',
	(r'^savewhatyoulookedat/login/
, login),
	(r'^savewhatyoulookedat/register/
, register)
)

As you can see above, the login function will be called when you try to access the following URL from your browser (or any other web client): http://localhost:8080/savewhatyoulookedat/login/

The ‘register’ function will be called when you try to access the following URL: http://localhost:8080/savewhatyoulookedat/register/

Note how the request object has been used along with some other objects that are the product of Django’s ORM. For example, in the login function, there is an instance of the Session model. The DB table behind the Session model is named Auth_session and it is specified in the models.py file above. Thus, whenever a user hits one of the URLs mentioned above, the view runs some DB queries and figures out what response to send to the client. This is how a RESTful application should work, and as you can see, Django really makes it easy to develop one.

Conclusion

Django is a very extensive framework, and since we were discussing REST applications, I deliberately left out Django templates. I will be explaining templates in another post, but since REST apps do not always need an HTML interface, I am skipping it for now. Also, we have just touched on some of the concepts of Django, and there is not enough room to discuss all of them in detail here. I would suggest that you go through this post, try and understand as best as you can, and then take a look at the official Django documentation for more details on the topic.

#python #django

What is GEEK

Buddha Community

How to Set Up a REST Service or a Web Application in Django
Hermann  Frami

Hermann Frami

1651383480

A Simple Wrapper Around Amplify AppSync Simulator

This serverless plugin is a wrapper for amplify-appsync-simulator made for testing AppSync APIs built with serverless-appsync-plugin.

Install

npm install serverless-appsync-simulator
# or
yarn add serverless-appsync-simulator

Usage

This plugin relies on your serverless yml file and on the serverless-offline plugin.

plugins:
  - serverless-dynamodb-local # only if you need dynamodb resolvers and you don't have an external dynamodb
  - serverless-appsync-simulator
  - serverless-offline

Note: Order is important serverless-appsync-simulator must go before serverless-offline

To start the simulator, run the following command:

sls offline start

You should see in the logs something like:

...
Serverless: AppSync endpoint: http://localhost:20002/graphql
Serverless: GraphiQl: http://localhost:20002
...

Configuration

Put options under custom.appsync-simulator in your serverless.yml file

| option | default | description | | ------------------------ | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | | apiKey | 0123456789 | When using API_KEY as authentication type, the key to authenticate to the endpoint. | | port | 20002 | AppSync operations port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20002, 20012, 20022, etc.) | | wsPort | 20003 | AppSync subscriptions port; if using multiple APIs, the value of this option will be used as a starting point, and each other API will have a port of lastPort + 10 (e.g. 20003, 20013, 20023, etc.) | | location | . (base directory) | Location of the lambda functions handlers. | | refMap | {} | A mapping of resource resolutions for the Ref function | | getAttMap | {} | A mapping of resource resolutions for the GetAtt function | | importValueMap | {} | A mapping of resource resolutions for the ImportValue function | | functions | {} | A mapping of external functions for providing invoke url for external fucntions | | dynamoDb.endpoint | http://localhost:8000 | Dynamodb endpoint. Specify it if you're not using serverless-dynamodb-local. Otherwise, port is taken from dynamodb-local conf | | dynamoDb.region | localhost | Dynamodb region. Specify it if you're connecting to a remote Dynamodb intance. | | dynamoDb.accessKeyId | DEFAULT_ACCESS_KEY | AWS Access Key ID to access DynamoDB | | dynamoDb.secretAccessKey | DEFAULT_SECRET | AWS Secret Key to access DynamoDB | | dynamoDb.sessionToken | DEFAULT_ACCESS_TOKEEN | AWS Session Token to access DynamoDB, only if you have temporary security credentials configured on AWS | | dynamoDb.* | | You can add every configuration accepted by DynamoDB SDK | | rds.dbName | | Name of the database | | rds.dbHost | | Database host | | rds.dbDialect | | Database dialect. Possible values (mysql | postgres) | | rds.dbUsername | | Database username | | rds.dbPassword | | Database password | | rds.dbPort | | Database port | | watch | - *.graphql
- *.vtl | Array of glob patterns to watch for hot-reloading. |

Example:

custom:
  appsync-simulator:
    location: '.webpack/service' # use webpack build directory
    dynamoDb:
      endpoint: 'http://my-custom-dynamo:8000'

Hot-reloading

By default, the simulator will hot-relad when changes to *.graphql or *.vtl files are detected. Changes to *.yml files are not supported (yet? - this is a Serverless Framework limitation). You will need to restart the simulator each time you change yml files.

Hot-reloading relies on watchman. Make sure it is installed on your system.

You can change the files being watched with the watch option, which is then passed to watchman as the match expression.

e.g.

custom:
  appsync-simulator:
    watch:
      - ["match", "handlers/**/*.vtl", "wholename"] # => array is interpreted as the literal match expression
      - "*.graphql"                                 # => string like this is equivalent to `["match", "*.graphql"]`

Or you can opt-out by leaving an empty array or set the option to false

Note: Functions should not require hot-reloading, unless you are using a transpiler or a bundler (such as webpack, babel or typescript), un which case you should delegate hot-reloading to that instead.

Resource CloudFormation functions resolution

This plugin supports some resources resolution from the Ref, Fn::GetAtt and Fn::ImportValue functions in your yaml file. It also supports some other Cfn functions such as Fn::Join, Fb::Sub, etc.

Note: Under the hood, this features relies on the cfn-resolver-lib package. For more info on supported cfn functions, refer to the documentation

Basic usage

You can reference resources in your functions' environment variables (that will be accessible from your lambda functions) or datasource definitions. The plugin will automatically resolve them for you.

provider:
  environment:
    BUCKET_NAME:
      Ref: MyBucket # resolves to `my-bucket-name`

resources:
  Resources:
    MyDbTable:
      Type: AWS::DynamoDB::Table
      Properties:
        TableName: myTable
      ...
    MyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: my-bucket-name
    ...

# in your appsync config
dataSources:
  - type: AMAZON_DYNAMODB
    name: dynamosource
    config:
      tableName:
        Ref: MyDbTable # resolves to `myTable`

Override (or mock) values

Sometimes, some references cannot be resolved, as they come from an Output from Cloudformation; or you might want to use mocked values in your local environment.

In those cases, you can define (or override) those values using the refMap, getAttMap and importValueMap options.

  • refMap takes a mapping of resource name to value pairs
  • getAttMap takes a mapping of resource name to attribute/values pairs
  • importValueMap takes a mapping of import name to values pairs

Example:

custom:
  appsync-simulator:
    refMap:
      # Override `MyDbTable` resolution from the previous example.
      MyDbTable: 'mock-myTable'
    getAttMap:
      # define ElasticSearchInstance DomainName
      ElasticSearchInstance:
        DomainEndpoint: 'localhost:9200'
    importValueMap:
      other-service-api-url: 'https://other.api.url.com/graphql'

# in your appsync config
dataSources:
  - type: AMAZON_ELASTICSEARCH
    name: elasticsource
    config:
      # endpoint resolves as 'http://localhost:9200'
      endpoint:
        Fn::Join:
          - ''
          - - https://
            - Fn::GetAtt:
                - ElasticSearchInstance
                - DomainEndpoint

Key-value mock notation

In some special cases you will need to use key-value mock nottation. Good example can be case when you need to include serverless stage value (${self:provider.stage}) in the import name.

This notation can be used with all mocks - refMap, getAttMap and importValueMap

provider:
  environment:
    FINISH_ACTIVITY_FUNCTION_ARN:
      Fn::ImportValue: other-service-api-${self:provider.stage}-url

custom:
  serverless-appsync-simulator:
    importValueMap:
      - key: other-service-api-${self:provider.stage}-url
        value: 'https://other.api.url.com/graphql'

Limitations

This plugin only tries to resolve the following parts of the yml tree:

  • provider.environment
  • functions[*].environment
  • custom.appSync

If you have the need of resolving others, feel free to open an issue and explain your use case.

For now, the supported resources to be automatically resovled by Ref: are:

  • DynamoDb tables
  • S3 Buckets

Feel free to open a PR or an issue to extend them as well.

External functions

When a function is not defined withing the current serverless file you can still call it by providing an invoke url which should point to a REST method. Make sure you specify "get" or "post" for the method. Default is "get", but you probably want "post".

custom:
  appsync-simulator:
    functions:
      addUser:
        url: http://localhost:3016/2015-03-31/functions/addUser/invocations
        method: post
      addPost:
        url: https://jsonplaceholder.typicode.com/posts
        method: post

Supported Resolver types

This plugin supports resolvers implemented by amplify-appsync-simulator, as well as custom resolvers.

From Aws Amplify:

  • NONE
  • AWS_LAMBDA
  • AMAZON_DYNAMODB
  • PIPELINE

Implemented by this plugin

  • AMAZON_ELASTIC_SEARCH
  • HTTP
  • RELATIONAL_DATABASE

Relational Database

Sample VTL for a create mutation

#set( $cols = [] )
#set( $vals = [] )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #set( $discard = $cols.add("$toSnake") )
  #if( $util.isBoolean($ctx.args.input[$entry]) )
      #if( $ctx.args.input[$entry] )
        #set( $discard = $vals.add("1") )
      #else
        #set( $discard = $vals.add("0") )
      #end
  #else
      #set( $discard = $vals.add("'$ctx.args.input[$entry]'") )
  #end
#end
#set( $valStr = $vals.toString().replace("[","(").replace("]",")") )
#set( $colStr = $cols.toString().replace("[","(").replace("]",")") )
#if ( $valStr.substring(0, 1) != '(' )
  #set( $valStr = "($valStr)" )
#end
#if ( $colStr.substring(0, 1) != '(' )
  #set( $colStr = "($colStr)" )
#end
{
  "version": "2018-05-29",
  "statements":   ["INSERT INTO <name-of-table> $colStr VALUES $valStr", "SELECT * FROM    <name-of-table> ORDER BY id DESC LIMIT 1"]
}

Sample VTL for an update mutation

#set( $update = "" )
#set( $equals = "=" )
#foreach( $entry in $ctx.args.input.keySet() )
  #set( $cur = $ctx.args.input[$entry] )
  #set( $regex = "([a-z])([A-Z]+)")
  #set( $replacement = "$1_$2")
  #set( $toSnake = $entry.replaceAll($regex, $replacement).toLowerCase() )
  #if( $util.isBoolean($cur) )
      #if( $cur )
        #set ( $cur = "1" )
      #else
        #set ( $cur = "0" )
      #end
  #end
  #if ( $util.isNullOrEmpty($update) )
      #set($update = "$toSnake$equals'$cur'" )
  #else
      #set($update = "$update,$toSnake$equals'$cur'" )
  #end
#end
{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> SET $update WHERE id=$ctx.args.input.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.input.id"]
}

Sample resolver for delete mutation

{
  "version": "2018-05-29",
  "statements":   ["UPDATE <name-of-table> set deleted_at=NOW() WHERE id=$ctx.args.id", "SELECT * FROM <name-of-table> WHERE id=$ctx.args.id"]
}

Sample mutation response VTL with support for handling AWSDateTime

#set ( $index = -1)
#set ( $result = $util.parseJson($ctx.result) )
#set ( $meta = $result.sqlStatementResults[1].columnMetadata)
#foreach ($column in $meta)
    #set ($index = $index + 1)
    #if ( $column["typeName"] == "timestamptz" )
        #set ($time = $result["sqlStatementResults"][1]["records"][0][$index]["stringValue"] )
        #set ( $nowEpochMillis = $util.time.parseFormattedToEpochMilliSeconds("$time.substring(0,19)+0000", "yyyy-MM-dd HH:mm:ssZ") )
        #set ( $isoDateTime = $util.time.epochMilliSecondsToISO8601($nowEpochMillis) )
        $util.qr( $result["sqlStatementResults"][1]["records"][0][$index].put("stringValue", "$isoDateTime") )
    #end
#end
#set ( $res = $util.parseJson($util.rds.toJsonString($util.toJson($result)))[1][0] )
#set ( $response = {} )
#foreach($mapKey in $res.keySet())
    #set ( $s = $mapKey.split("_") )
    #set ( $camelCase="" )
    #set ( $isFirst=true )
    #foreach($entry in $s)
        #if ( $isFirst )
          #set ( $first = $entry.substring(0,1) )
        #else
          #set ( $first = $entry.substring(0,1).toUpperCase() )
        #end
        #set ( $isFirst=false )
        #set ( $stringLength = $entry.length() )
        #set ( $remaining = $entry.substring(1, $stringLength) )
        #set ( $camelCase = "$camelCase$first$remaining" )
    #end
    $util.qr( $response.put("$camelCase", $res[$mapKey]) )
#end
$utils.toJson($response)

Using Variable Map

Variable map support is limited and does not differentiate numbers and strings data types, please inject them directly if needed.

Will be escaped properly: null, true, and false values.

{
  "version": "2018-05-29",
  "statements":   [
    "UPDATE <name-of-table> set deleted_at=NOW() WHERE id=:ID",
    "SELECT * FROM <name-of-table> WHERE id=:ID and unix_timestamp > $ctx.args.newerThan"
  ],
  variableMap: {
    ":ID": $ctx.args.id,
##    ":TIMESTAMP": $ctx.args.newerThan -- This will be handled as a string!!!
  }
}

Requires

Author: Serverless-appsync
Source Code: https://github.com/serverless-appsync/serverless-appsync-simulator 
License: MIT License

#serverless #sync #graphql 

Lets Cms

Lets Cms

1652251528

Opencart REST API extensions - V3.x | Rest API Integration, Affiliate

Opencart REST API extensions - V3.x | Rest API Integration : OpenCart APIs is fully integrated with the OpenCart REST API. This is interact with your OpenCart site by sending and receiving data as JSON (JavaScript Object Notation) objects. Using the OpenCart REST API you can register the customers and purchasing the products and it provides data access to the content of OpenCart users like which is publicly accessible via the REST API. This APIs also provide the E-commerce Mobile Apps.

Opencart REST API 
OCRESTAPI Module allows the customer purchasing product from the website it just like E-commerce APIs its also available mobile version APIs.

Opencart Rest APIs List 
Customer Registration GET APIs.
Customer Registration POST APIs.
Customer Login GET APIs.
Customer Login POST APIs.
Checkout Confirm GET APIs.
Checkout Confirm POST APIs.


If you want to know Opencart REST API Any information, you can contact us at -
Skype: jks0586,
Email: letscmsdev@gmail.com,
Website: www.letscms.com, www.mlmtrees.com
Call/WhatsApp/WeChat: +91–9717478599.

Download : https://www.opencart.com/index.php?route=marketplace/extension/info&extension_id=43174&filter_search=ocrest%20api
View Documentation : https://www.letscms.com/documents/api/opencart-rest-api.html
More Information : https://www.letscms.com/blog/Rest-API-Opencart
VEDIO : https://vimeo.com/682154292  

#opencart_api_for_android #Opencart_rest_admin_api #opencart_rest_api #Rest_API_Integration #oc_rest_api #rest_api_ecommerce #rest_api_mobile #rest_api_opencart #rest_api_github #rest_api_documentation #opencart_rest_admin_api #rest_api_for_opencart_mobile_app #opencart_shopping_cart_rest_api #opencart_json_api

Rahim Makhani

Rahim Makhani

1621483980

Get the best web app for your Business FUTURE

The web app is application software that runs on the webserver. You can easily use the web app by searching it in the web browser through Google or any other search engine, or you can also add shortcuts of the web app to your smartphone.

Web app for your business helps you to reach new customers and enables them to know about your firm and the services you provide and can know about your organization’s feedback and rating. It can also help you with the advertisement of your app among all.

Do you want to develop a web app for your business? Then it would help if you collaborated with Nevina Infotech, which is the best web application development company that will help you develop a unique web app with the help of its dedicated developers.

#web application development company #web application development services #web app development company #custom web application development company #web app development services #custom web application development services

Rahim Makhani

Rahim Makhani

1626238039

Find the best web app development company for your Startup

A web app is the best way to promote their business for startups. You can’t verbally go and tell everyone to visit your company, but your website or web app can do that. A web app can represent your company, and the visitors who are visiting your website or web app will get knowledge about your firm. Doing this can help you to increase your customer rate.

Nevina Infotech is the best web app development company to choose for developing your web app for your startup. We have a great team of web developers to work with. Our developers are dedicated and enthusiastic in their work.

#web application development company #web application development services #web app development company #custom web application development company #web app development services #custom web application development services

Rahim Makhani

Rahim Makhani

1627274472

Develop An Unique Web App for your Firm

Web app represents the particular firm or organization for which it is developed. With the help of a web app, the firm owner can promote and increase their business by reaching more and more customers for their website or web app.

Every firm or organization must have its own web app to represent their company, what they do, what they provide users feedback, and a lot more. If you have your web app then users can know your company deeply and they can also show interest in your company.

To develop a unique web app contact Nevina Infotech that is the best web application development services provider company, that can help you to develop the web app for your firm as per your requirement.

#web application development company #web application development services #web app development company #custom web application development company #web app development services #web application development agency