Advanced Functionality
Once you have completed installation, you will next need to configure your environment. Follow these configuration steps in order to get your environment setup and working:
Automated Batching
Have you ever had someone from marketing or sales come to you and say 'Hey I'm tired of entering these one at a time. Can you make it so I can enter 50 or 100 of these at once through the API?' Well you just created a Batch API. But why create them when you can just use the existing endpoints? BeAPI automates everything so you don't have to create 'batch api's'; ALL API's are batchable! You merely have to set the proper authorities for those endpoints in your IO State File.
Once added, a batch call can be made simply like this:
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer " --request POST -d "{'combine':true,'batch': [{'name': 'test1'},{'name': 'test2'},{'name': 'test3'},{'name': 'test4'},{'name': 'test5'},{'name': 'test6'}]}" http://localhost:8080/b1.0/test/create
In the example above, the 'combine' flag lets us know to concatenate the output into a single response. Otherwise it will only return the last 'element' for this response.
This is important if you are doing batch INSERTS and don't care about the output (unless there is an EXCEPTION thrown).
NOTE ON VERSIONING: Of importance to note is that the versioning used here is b1.0 ('b' plus the application 'version' as found in build.gradle - see Usage). We do this so that we can separate this functionality out to a separate server if we want so as not to affect main api calls. Same goes for API chaining calls which use 'c1.0'.
Batch Examples Using Curl
Below are example of batch calls taken directly from the integration tests in the framework to give you an example of how to write them:
POST Batch Call EXAMPLE (no concatenation)
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer " --request POST -d "{'batch': [{'name': 'test1'},{'name': 'test2'},{'name': 'test3'},{'name': 'test4'},{'name': 'test5'},{'name': 'test6'}]}" http://localhost:8080/b1.0/test/create
GET Batch Call EXAMPLE (with concatenation)
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer " --request POST -d "{'combine':true,'batch': [{'id': '1'},{'id': '2'},{'id': '3'},{'id': '4'},{'id': '5'},{'id': '6'}]}" http://localhost:8080/b1.0/test/show
DELETE Batch Call EXAMPLE (with concatenation)
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer " --request POST -d "{'combine':true,'batch': [{'id': '1'},{'id': '2'},{'id': '3'},{'id': '4'},{'id': '5'},{'id': '6'}]}" http://localhost:8080/b1.0/test/delete
CSV To JSON Tools
Alot of people in your organization may will be asking for help with CSV to JSON conversion. So here are some links to CSV to JSON tools:
Automated Webhooks
A Web Hook is a way to notify a user of a change to data whenever it occurs. Of course, you don't always WANT users to see all the changes to all your data so you want to be very careful who you expose your web hooks to!
Enabling Your Endpoint To Be Hookable
Every endpoint in the framework has the ability to be hookable via your IO State files which can be found in your '~/.beapi/.iostate/' directory.
Webhooks are optional and are not turned on by default. You can set this variable PER ENVIRONMENT in your '~/.beapi/beapi_server.yml' file by changing the variable 'webhookActive' in your environment to 'true'. The default is:
webhookActive: false
Simply modify the HOOK section in your IO State file for the endpoint of the controller you want to add a hook to in the iostate file by adding a new role. For example, if I wanted to add a new role to the 'person/create' endpoint which looks like the following:
...
"create": {
"METHOD":"POST",
"DESCRIPTION":"Create new Person",
"ROLES":{
"DEFAULT":["ROLE_ADMIN","ROLE_USER"],
"BATCH":["ROLE_ADMIN"],
"HOOK":["ROLE_ADMIN"]
},
"REQUEST": {
"permitAll":["username","password","email"]
},
"RESPONSE": {
"permitAll":["id","version"]
}
}
...
For example... if you wanted to allow USER ROLE to access webhooks for the 'create' api, you simple add the role to HOOK like so:
...
"create": {
"METHOD":"POST",
"DESCRIPTION":"Create new Person",
"ROLES":{
"DEFAULT":["ROLE_ADMIN","ROLE_USER"],
"BATCH":["ROLE_ADMIN"],
"HOOK":["ROLE_ADMIN","ROLE_USER"]
},
"REQUEST": {
"permitAll":["username","password","email"]
},
"RESPONSE": {
"permitAll":["id","version"]
}
}
...
NOTE: All roles have to exist in the 'networkRoles' for the IO State files 'NETWORKGRP'. See 'Security: Cors / Network Roles'
Create Your First Webhook
To create your first webhook, setup an URL endpoint on a separate service (like AWS Lambda) that we can forward the data to. Enter the url (or IP) into your CORS 'allowedOrigins' in your ~/.beapi/beapi.yml. This will be defined as your URL in your webhook.
Finally, go into your database for your application and type the following SQL Query:
select id from person where email='[your_email]';
// this is how you get your user id
insert into hook (attempts,date_created,format,last_modified,user_id,is_enabled,url,service) values(0,NOW(),'JSON',NOW(),[your_user_id],true,'[your_url]','[your_service]');
And there you have it! Your first webhook!
API Chaining®
API Chaining is a trademark for a group of processes (herein embodied in libraries and services) allowing one api call to return data to another api call by using the pre-established primary/foreign key relation from data records (ie ERDB) to connect the data and return it into another api call , etc etc, all within ONE REQUEST/RESPONSE. there is no 'chaining' of REQUESTS because it only uses a SINGLE REQUEST/RESPONSE. This is allowed through the abstraction of communication logic from business logic through the New API Pattern. This is limited in the fact that you can only use GET method as the connectors in the chain and one other 'non-safe' method (ie PUT/POST/DELETE) at either the beginning or the end of the chain (as determined by the REQUEST method).
NOTE: The API Chaining trademark can only be used by those properly implementing the process. As a process, it is only considered successfully implemented if:
- API call MUST use ONLY ONE REQUEST/RESPONSE (ie no redirects)
- Client can create chains and they MUST be processed dynamically; there SHOULD BE NO hardcoded chains.
- There MUST BE no more than ONE non-safe REQUEST method used in a chain during a single REQUEST/RESPONSE
What Is API Chaining®?
We have all used encoded GET data when sending form data via a POST request. This is considered common practice. Why? Because GET is idempotent and SAFE. Because it is SAFE (meaning it doesn't change data), it is commonly used with other types of requests as a mixed request. This may not be RESTful but it is considered normal and not unsafe. This is what I like to refer to as a single link chain since it has only one link which is the same as it's destination request.
API chaining extends upon this principle in the fact that you can encode GET data in the URL but pass a POST/PUT/DELETE request (much like post GET with a POST form) to chain the request TO or FROM the request method destination link. This can be used to imply GET requests chained TO a final request link (known as a post- chain) or FROM a request link to other implied GET links (known as a pre-chain).
The reason why this is better than practices like HATEOAS/HAL is that it doesn't rely on the link for the relationship... it relies on a common API Object. By relying on a common API Object to apply rules, endpoints/URI's then only become a reference point for data.
For example, when we make our PUT/POST/DELETE requests we can do :
- a post-chain request: a GET request that return the data, then specifies the key we wish to pass to the next 'link' in the chain which will make a GET request returning data, etc until the final request method is matched. This can be illustrated as follows:
GET > GET > GET > PUT
- a pre-chain request: same as a post chain request except the request method is matched in the beginning and then sends and id to the GET methods after it is called. This can be illustrated as follows:
POST > GET > GET
- a blank chain request (AKA a 'GET' chain): a blank chain has no additional method; it is merely a series of chained GET requests. Basically this takes the returned data from one GET and you give the KEY to get the data for the next GET request in the chain (just like in other chains).
GET > GET > GET > GET > GET
NOTE: Pre and Post chain example can happen with any method including DELETE; A Delete method can delete data or just render it 'inactive' (depending on your controller and domain setup) so passing the ID to a GET method after a DELETE can be useful to get related data or to confirm the state.
API Chaining® Example
POST Post-Chain Example (minus the data)
The POST post-chain would be encoded as follows:
{
companyName:'Amazon',
address:'549 S. Dawson',
zip:'98108',
chain:{
key:dept_id,
combine:'false',
type:'postchain',
order:{dept/show:company_id,company/update:return}
}
}
And then call via Curl (or via javascript) as follows:
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer [access token]" -X POST -d "{'companyName':'Amazon','address': '549 S. Dawson','zip': '98108','chain':{ 'key':'dept_id','combine':'false','type':'postchain','order':{'dept/show':'company_id','company/update':'return'}}}" "http://localhost:8080/v1.0/person/show/1"
Creating A Chain
Now lets break down how this call work. Normally you could never pass more than one method but you can URL encode GET data with UNSAFE Methods (PUT, POST, DELETE); now by only using one unsafe method for the call and only one unsafe method, we can send AS MANY GETS in the chain as we want!
So the rules of a chain are:
- You can have only one PUT,POST or DELETE endpoint per chain
- You can have unlimited GET endpoints in a chain
- The unsafe method (PUT/POST/DELETE) must begin/end the chain
- Chains MUST be called using 'c' followed by the application 'version' (as found in build.gradle) 'b' plus the application 'version' as found in build.gradle - see Usage
Now lets examine how one of the above chain works:
- http://localhost:8080/c0.1/person/show/1: initial endpoint that retrieves the initial dataset
- key : dept_id: the key to return from the initial dataset to the next iteration in the chain
- combine:false: whether to concatenate all data in the chain for return
- type:postchain: tells us the location of the unsafe method in the chain for processing; 'postchain' tells us it is at the end, 'prechain' tells us it is at the beginning.
- dept/show : company_id: second endpoint iteration; id is the key returned for the next iteration in the chain
- company/update : return: As this is the final iteration (and this is a post chain), we return from the chain here
So given the chain above, we can see that the unsafe method(PUT) is at the end of the chain (section/update). We also KNOW that it is there because it was DECLARED as a 'postchain' (rather than 'prechain')
Architecture PING
BeAPI gives you the ability to 'ping' all the api servers in your architecture to test for uptime. You can do this by using the following command:
curl -v -H "Content-Type: application/json" -H "Authorization: Bearer " --request GET "http://localhost:8080/v1.0/server/pingServers/"
Rate Limiting
Rate Limiting is optional and is not turned on by default. You can set this variable PER ENVIRONMENT in your 'beapi_server.yml' file by changing the variable 'apiThrottle' in your environment to 'true':
apiThrottle: true
Rate limiting needs to be configured on a per ROLE basis; that is to say; for each ROLE you want to apply rate limiting to, you need to create the rules for it in the 'beapi_api.yml' file. Lets take a look at that section:
throttle:
rateLimit: {'ROLE_USER':1000,'ROLE_ADMIN':10000}
dataLimit: {'ROLE_USER':1000000,'ROLE_ADMIN':1000000}
# in seconds (3600 = 60 minutes)
expires: 3600
Lets examine the above settings and break them down:
- rateLimit: This sets the 'count' for the number of requests that are allowed to be done within the day. After this is hit (or goes over the limit), a lock is put on the account until 'expires' clock runs out.
- dataLimit: This is not yet implemented. This will eventually mark the MB limit before a lock is place on the account.
- expires: This sets the number of seconds until a rateLimit lock is released. Ideally this should be a day but we have it currently set low.