SlideShare a Scribd company logo
Building Quick APIs
by Gavin Pickin
https://github.com/gpickin/itb2021-building-quick-apis
Building Quick APIs
by Gavin Pickin
https://github.com/gpickin/itb2021-building-quick-apis
Gavin Pickin
Who am I?
• Software Consultant for Ortus Solutions
• Work with ColdBox, CommandBox, ContentBox
APIs and VueJS every day!
• Working with Coldfusion for 22 years
• Working with Javascript just as long
• Love learning and sharing the lessons learned
• From New Zealand, live in Bakersfield, Ca
• Loving wife, lots of kids, and countless critters
@gpickin
What is this talk?
We will setup a secure API using fluent query language - and
you’ll see how quick Quick development can be!
We will use
● ColdBox
● ColdBox’s built in REST BaseHandler
● Route Visualizer
● CBSecurity
● Quick ORM
What is this talk not?
● We will not be adding an API to a Legacy Site
● We will not be adding an API to a non ColdBox site
● It is not my CF Meetup Talk “Building APIs with
ColdFusion Part 1”
https://www.youtube.com/watch?v=UdgRt8HIKD0
BUT YOU COULD DO ALL OF THESE THINGS
WITH THE KNOWLEDGE FROM THIS TALK
Why should I give this talk?
• I build a lot of APIs for Customers
• I have seen many different ways to build an API
• I’m going to share some of the lessons I have learned.
• I try to present in step by step follow along later
format that I think you’ll love
• Hopefully you’ll learn something
• Hopefully it will be useful.
What is an API?
API is an application programming interface
More commonly when someone says API today they think of
an JSON API, usually we hope for a REST API but not always.
APIs can be xml, soap, but it’s very common to talk about
JSON apis, and that’s what we’re talking about today.
Although most of it is relatable.
REST JSON API vs JSON API
What is REST
REST is acronym for REpresentational State Transfer. It is
architectural style for distributed hypermedia systems and
was first presented by Roy Fielding in 2000 in his famous
dissertation.
All REST are APIs but not all APIs are REST.
Guiding Principles of REST
● Client–server
● Stateless
● Cacheable
● Uniform interface
● Layered system
The key abstraction of information in REST is a resource. Any information
that can be named can be a resource: a document or image, a temporal
service, a collection of other resources, a non-virtual object (e.g. a person),
and so on. REST uses a resource identifier to identify the particular resource
involved in an interaction between components.
What App are we working on?
SOAPBOX API - An API for a twitter clone we built for our ColdBox Zero to Hero Training.
Let’s do this!!!
Start up CommandBox!!!
Create a ColdBox App
box coldbox create app soapbox-api
This installs:
● ColdBox
● TestBox
● CommandBox-dotEnv
● CommandBox-cfconfig
● CommandBox-cfformat
Let’s update our .env
● Change the connection string to match our DB - soapboxapi
● Change the DB_DATABASE to match our DB - soapboxapi
● Change ports, user name and password to match
Let’s start our server
That port matches the testbox runner in the box.json
http://127.0.0.1:53163/ - our site
http://127.0.0.1:53163/tests/runner.cfm - our tests
box start port=53163
Let’s plan our API
What is an Example URL - /api/v01/users
We’re going to make API a module with a V01 module inside of it.
● Add modules_app folder for this apps custom modules
● Add modules_app/api folder with ModuleConfig.cfc
● Add modules_app/api/modules/api-v01 folder with ModuleConfig.cfc
API - V01
Let’s build out our API V01 Module
● Add modules_app/api/modules/api-v01/config Folder with Router.cfc
● Setup the base route of “/” to go to main.index
● Add api-v01/handlers/main.cfc which extends coldbox.system.RestHandler
● Add index event in the main handler
● Index event should sets data in the response object to welcome the user to
the api.
http://127.0.0.1:53163/api/v01
API - V01
Let’s plan our API
USER resource
GET /api/v02/users - get a list of users
POST /api/v02/users - create a new user
GET /api/v02/users/:userID - get a single user
POST /api/v02/users/:userID - update a single user
DELETE /api/v02/users/:userID - delete a single user
API - V02
Add User Resource to Router.cfc
resources(
resource = "users",
handler = "users",
parameterName = "userID",
only = [ "index", "show", "create", "update", "delete" ]
);
API - V02
Let’s view our Routes
box install route-visualizer
API - V02
Build our Users Handler
function index( event, rc, prc ){
event.getResponse().setData( "List Users" );
}
function create( event, rc, prc ){
event.getResponse().setData( "Create User" );
}
API - V02
http://127.0.0.1:53163/api/v02/users
Secure our CUD Actions
Let’s use CBSecurity to lock down our non READ functionality
● CREATE
● UPDATE
● DELETE
API - V03
Install CBSecurity
Add the Config to your config/ColdBox.cfc
Add a JWT Secret incase .env has a blank one
Add “api-v03:main.index” for “invalidAuthenticationEvent”
Add “api-v03:main.index” for “invalidAuthorizationEvent”
API - V03
box install cbsecurity
Add Secured Metadata
function create( event, rc, prc ) secured{
event.getResponse().setData( "Create Users" );
}
API - V03
Check our Security
http://127.0.0.1:53163/api/v03/users?_method=post
You will get redirected to main.index
API - V03
Updating Redirects for API Authentication
and Authorization Issues
You should really setup your main ColdBox app for an HTML page and
your API module for an API page
Add settings to the API-v04 Module Config
Add “api-v04:main.index” for “invalidAuthenticationEvent”
Add “api-v04:main.index” for “invalidAuthorizationEvent”
API - V04
Updating Redirects for API Authentication
and Authorization Issues
http://127.0.0.1:53163/api/v04/users/?_method=post
Now we are redirected to an API Handler
You can add new methods for onInvalidAuth and or
onInvalidAuthorization to be more specific in your responses
API - V04
Install and Configure Quick
add a datasource definition in Application.cfc
API - V05
this.datasource = "soapboxapi";
box install quick
Create our Quick User Entity
component extends="quick.models.BaseEntity" accessors="true" {
property name="id" type="string";
property name="username" type="string";
property name="email" type="string";
property name="password" type="string";
}
API - V05
Quick is Smart
● Quick guesses the table is named Users because the entity is User
● Quick guesses the Primary Key is ID
● Quick uses the Datasource defined in the Application.cfc
● Quick can make a Virtual Service for us from a WireBox Injection
property name="userService" inject="quickService:User@api-v05";
Quick does a lot for us
API - V05
Show a User
function show( event, rc, prc ){
event.paramValue( "userID", 0 );
event.getResponse().setData(
userService
.findOrFail( rc.userID )
.getMemento()
);
}
API - V05
Show a User
http://127.0.0.1:53163/api/v05/users/2
API - V05
What if we can’t find that User?
http://127.0.0.1:53163/api/v05/users/x
404 response
API - V05
Return a list of Users
function index( event, rc, prc ){
event.getResponse().setData(
userService
.asMemento()
.get()
);
}
API - V06
What is asMemento()
asMemento() is a special function that tells quick you want to map over
all of the objects in the array, and call getMemento() on all of the items
.get().getMemento() doesn’t work because .get() returns an array
As memento is essentially the following done for you.
...get().map( (item) => { return item.getMemento() } );
API - V06
Reinit and check the API
http://127.0.0.1:53163/api/v06/users/
API - V06
Configuring Mementifier
● We don’t want to return all of the fields
● For example Password, even if it is encrypted
https://github.com/coldbox-modules/mementifier
API - V07
Mementifier Inline Excludes
API - V07
userService
.asMemento(
excludes=[ "password" ]
)
.get()
http://127.0.0.1:53163/api/v07/users
Mementifier - Inline Includes
API - V08
userService
.asMemento(
includes=[ "id", "username", "email" ],
ignoreDefaults = true
)
.get()
http://127.0.0.1:53163/api/v08/users
Mementifier - Entity Config
API - V09
//models/User.cfc
this.memento = {
defaultIncludes=[ "username", "email" ],
neverInclude=["password"]
}
http://127.0.0.1:53163/api/v09/users/2
Mementifier - Inline Includes
API - V10
function index( event, rc, prc ){
event.getResponse().setData(
userService
.asMemento(
includes=[ “ID” ]
)
.get()
);
}
http://127.0.0.1:53163/api/v10/users/
Using Where to Filter Users
API - V11
event.paramValue( "username_filter", "" );
event.getResponse().setData(
userService
.where( "username", "like", '%#rc.username_filter#%')
.asMemento(
includes="ID"
)
.get()
);
http://127.0.0.1:53163/api/v11/users?username_filter=gp
Using Scope to Filter Users
API - V12
//handler - use this
userService.whereUsernameLike(rc.username_filter)
// not this
userService.where( "username", "like", '%#rc.username_filter#%')
// models/User.cfc
function scopeWhereUsernameLike( qb, filter ){
qb.where( "Username", "like", '%#filter#%' )
}
http://127.0.0.1:53163/api/v12/users?username_filter=gp
Using Dynamic Where to Match Users
API - V13
userService
.whereUsernameLike(rc.username_filter)
.whereUsername(rc.username)
.asMemento(
includes="ID"
)
.get()
http://127.0.0.1:53163/api/v13/users?username_filter=gp
Using When for Empty Variables
API - V14
userService
.whereUsernameLike(rc.username_filter)
.when( len( rc.username ), function( q ) {
q.whereUsername(rc.username)
}
.asMemento(
includes="ID"
)
.get()
http://127.0.0.1:53163/api/v14/users?username_filter=gp
Using When for Empty Variables
API - V14
userService
.whereUsernameLike(rc.username_filter)
.when( len( rc.username ), function( q ) {
q.whereUsername(rc.username)
}
.asMemento(
includes="ID"
)
.get()
http://127.0.0.1:53163/api/v14/users?username=gp
Using When for Empty Variables
API - V14
userService
.whereUsernameLike(rc.username_filter)
.when( len( rc.username ), function( q ) {
q.whereUsername(rc.username)
}
.asMemento(
includes="ID"
)
.get()
http://127.0.0.1:53163/api/v14/users?username=gpickin
Using ‘Or’ for Similar Filters
API - V15
userService
.whereUsernameLike(rc.username_filter)
.when( len( rc.username ), function( q ) {
q.whereUsername(rc.username)
}
.asMemento(
includes="ID"
)
.get()
http://127.0.0.1:53163/api/v14/users?username=gpickin&username_filter=luis
Using ‘Or’ for Similar Filters
API - V15
userService
.whereUsernameLike(rc.username_filter)
.orWhere( function(q){
q.when( len( rc.username ), function( q2 ) {
q2.orwhereUsername(rc.username)
})
})
http://127.0.0.1:53163/api/v14/users?username=gpickin&username_filter=lui
Setup Rant Resource
API - V16
resources(
resource = "rants",
handler = "rants",
parameterName = "rantID",
only = [ "index", "show", "create", "update", "delete" ]
);
Setup Rant Handler
API - V16
/**
* Manage Rants API Handler
*
*/
component extends="coldbox.system.RestHandler "{
/**
* Display a list of Rants
*/
function index( event, rc, prc ){
event.getResponse().setData( "Show Rants");
}
/**
* Create a Rant
*/
Test Rant Resource
API - V16
http://127.0.0.1:53163/api/v16/rants? http://127.0.0.1:53163/api/v16/rants/6
Create Rant Entity
API - V17
component extends="quick.models.BaseEntity" accessors="true" {
property name="id" type="string";
property name="body" type="string";
property name="createdDate" type="date";
property name="modifiedDate" type="date";
property name="userID" type="string";
}
Inject Rant Service and Return Rants
API - V17
property name="rantService" inject="quickService:Rant@api-v17";
function index( event, rc, prc ){
event.getResponse().setData(
rantService
.asMemento()
.get()
);
}
http://127.0.0.1:53163/api/v17/rants
Paginate the Rants Returned
API - V18
http://127.0.0.1:53163/api/v17/rants
● We don’t want to return every record, it will only
grow longer and longer over time, and
performance will suffer
● ColdBox RESTBaseHandler already has Pagination
information
● Let’s use Quick’s Paginate function
Paginate the Rants Returned
API - V18
http://127.0.0.1:53163/api/v18/rants
event.getResponse().setData(
rantService
.asMemento()
.paginate(1,10)
);
Paginate the Rants Returned
API - V18
http://127.0.0.1:53163/api/v18/rants
event.getResponse().setData(
rantService
.asMemento()
.paginate(1,10)
);
Why do we have 2 sets of Pagination Data???
Use SetDataWithPagination
API - V19
http://127.0.0.1:53163/api/v19/rants
event
.getResponse()
.setDataWithPagination(
rantService
.asMemento()
.paginate(1,10)
);
Return Rants User Information
// Add User Relationship to Rant.cfc
function user(){
return hasOne( "User@api-v20", "id", "userID" );
}
API - V20
// Update Rants.cfc handler
event.getResponse().setDataWithPagination(
rantService
.asMemento( includes="user" )
.paginate(1,10)
);
Return Rants User Information
API - V20
http://127.0.0.1:53163/api/v20/rants
Return Rants User Information
API - V20
● Nested Fields
● What if we just want 1 field?
● How is Mementifier getting the
data??
http://127.0.0.1:53163/api/v20/rants
Return Rants with SubSelect User Information
API - V21
event.getResponse().setDataWithPagination(
rantService
.addSubselect( "username", "user.username")
.asMemento()
.paginate(1,10)
);
http://127.0.0.1:53163/api/v21/rants
Return a Count of Rants for Users
API - V22
// Add Rants Relationship to models/User.cfc
function rants(){
return hasMany( "Rant@api-v22", "userID", "id" );
}
// Update users.cfc handler
userService
.withCount( "rants" )
.asMemento(
includes=["ID","rantsCount"]
)
.get()
http://127.0.0.1:53163/api/v22/users
Return Recent Rants for Users
API - V23
//Router.cfc
get( "/users/:userID/rants"
, "userRants.index" );
// Handlers/userRants.cfc
function index( event, rc, prc ){
event.paramValue( "userID", "" );
event.paramValue( "page", 1 );
event.paramValue( "per_page", 10 );
event.getResponse().setDataWithPagination
(
rantService
.where( "userID", rc.userID )
.orderBy( "createdDate", "desc" )
.asMemento()
.paginate( rc.page, rc.per_page )
);
}
http://127.0.0.1:53163/api/v23/users/2/rants
Create a new Rant
API - V24
http://127.0.0.1:53163/api/v24/rants?_method=post&userID=2&body=Adding%20a%20Rant
function create( event, rc, prc ){
event.paramValue( "userID", "" );
event.paramValue( "body", "" );
userService
.findOrFail( rc.userID )
.rants()
.create( { body: rc.body } );
event.getResponse().setData( "Rant Created" );
}
View the new Rant
API - V24
http://127.0.0.1:53163/api/v24/users/2/rants
What if we add an Empty Rant
API - V24
http://127.0.0.1:53163/api/v24/rants?_method=post&userID=2&body=
Not User
Friendly
Validate a new Rant
API - V25
box Install cbvalidation
Validate a new Rant - Handler Constraints
API - V25
var validationResult = validate(
target = rc,
constraints = { body : { required : true } }
)
if ( !validationResult.hasErrors() ) {
// Normal API Response
} else {
event.getResponse()
.setError( true )
.addMessage( validationResult.getAllErrors() )
.setStatusCode( 400 )
.setStatusText( "Validation error" );
}
http://127.0.0.1:53163/api/v25/rants?_method=post&userID=2&body=
Validate a new Rant - Entity Constraints
API - V26
//Rant.cfc
this.constraints = {
body : { required : true },
userID: { required : true, type : "numeric" }
};
// Handler/rants.cfc
var rant = getInstance( "Rant@api-v26" )
.fill({ body: rc.body, userID: rc.userID });
validateOrFail( rant );
var user = userService.findOrFail( rc.userID );
rant.save();
event.getResponse().setData( "Rant Created" );
Validate a new Rant - Entity Constraints
API - V26
http://127.0.0.1:53163/api/v26/rants?_method=post&userID=2&body=
Body is missing or empty
Validate a new Rant - Entity Constraints
API - V26
http://127.0.0.1:53163/api/v26/rants?_method=post&userID=xxx&body=MyRant
UserID is not numeric
Validate a new Rant - Entity Constraints
API - V26
http://127.0.0.1:53163/api/v26/rants?_method=post&userID=0&body=MyRant
UserID is numeric but not in User table
Edit a Rant
API - V27
event.paramValue( "rantID", 0 );
event.paramValue( "body", "" );
var rant = rantService.findOrFail( rc.rantID )
.fill({ body: rc.body });
validateOrFail( rant );
rant.save();
event.getResponse().setData( "Rant Updated" );
Edit a Rant - Success
API - V27
http://127.0.0.1:53163/api/v27/rants/178/?_method=put&body=Yes%20thats%20is%20right
Edit a Rant - Missing Body
API - V27
http://127.0.0.1:53163/api/v27/rants/178/?_method=put&body=
Delete a Rant
API - V28
function delete( event, rc, prc ){
event.paramValue( "rantID", 0 );
var rant = rantService.findOrFail( rc.rantID ).delete();
event.getResponse().setData( "Delete a Rant" );
}
Delete a Rant that doesn’t Exist
API - V28
http://127.0.0.1:53163/api/v28/rants/70000/?_method=delete
Delete a Rant that does Exist
API - V28
http://127.0.0.1:53163/api/v28/rants/7/?_method=delete
Secure the Add / Edit Rant
function create( event, rc, prc ) secured{ … }
function update( event, rc, prc ) secured{ … }
API - V29
NOT LOGGED IN
http://127.0.0.1:53163/api/v29/rants/178/?_method=put&body=hiya
Secure the Delete Rant with a Special Permission
API - V29
function delete( event, rc, prc ) secured="RANT__DELETE"{ … }
http://127.0.0.1:53163/api/v29/rants/7/?_method=delete
NOT LOGGED IN
Create a Generate JWT Endpoint
//Router.cfc
post( "/login", "session.create" );
delete( "/logout", "session.delete" );
//handlers/session.cfc
function create( event, rc, prc ){
token = jwtAuth().fromuser( userService.findOrFail( 2 ) );
event.getResponse()
.addMessage( "Token Created" )
.setData( token );
}
function delete( event, rc, prc ){
jwtAuth().logout();
event.getResponse().setData( "Delete Session - Log Out" );
}
API - V30
Decorate User.cfc Entity for JWT
API - V30
/**
* A struct of custom claims to add to the JWT token
*/
struct function getJWTCustomClaims(){
return {};
}
/**
* This function returns an array of all the scopes that should be attached to the JWT
* token that will be used for authorization.
*/
array function getJWTScopes(){
return [];
}
Hit Generate JWT Endpoint
API - V30
http://127.0.0.1:53163/api/v30/login?_method=post
Use JWT to Add a Rant
API - V30
But Wait, there’s more (I wish)
I really wanted to show you more, but we don’t have all day.
Join me at the CF Online Meetup where I do this again, maybe
slower/better
Join me for the October Ortus Webinar as we build on top of this.
We might make a CFCasts series out of this if you like this style of
content
You can use images and add them opacity at 90%. This will blend the image
with the gradient background. This is a good option for subtitles also.
Testing APIs with TestBox
with Javier Quintero
Up Next
E-mail: gavin@ortussolutions.com
Twitter: @gpickin
Gavin Pickin
Senior Software Consultant
Ortus Solutions, Corp
https://github.com/gpickin/itb2021-building-quick-apis

More Related Content

What's hot

KB 1 Tindakan Operatif Kebidanan
KB 1 Tindakan Operatif KebidananKB 1 Tindakan Operatif Kebidanan
KB 1 Tindakan Operatif Kebidanan
pjj_kemenkes
 
บท1การแบ่งเซลล์
บท1การแบ่งเซลล์บท1การแบ่งเซลล์
บท1การแบ่งเซลล์
Wichai Likitponrak
 
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
surapha97
 
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluargaPemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
Rahayu Pratiwi
 
เฉลยO netวิทย์ชีวะ58
เฉลยO netวิทย์ชีวะ58เฉลยO netวิทย์ชีวะ58
เฉลยO netวิทย์ชีวะ58
Wichai Likitponrak
 
Acropora cervicornis
Acropora  cervicornisAcropora  cervicornis
Acropora cervicornis
Yoga Prikitiew
 
G biology bio2
G biology bio2G biology bio2
G biology bio2Bios Logos
 

What's hot (8)

KB 1 Tindakan Operatif Kebidanan
KB 1 Tindakan Operatif KebidananKB 1 Tindakan Operatif Kebidanan
KB 1 Tindakan Operatif Kebidanan
 
บท1การแบ่งเซลล์
บท1การแบ่งเซลล์บท1การแบ่งเซลล์
บท1การแบ่งเซลล์
 
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
ชุดกิจกรรมการเรียนรู้ เรื่องการถ่ายทอดลักษณะทางพันธุกรรมและความหลากหลายทางชีว...
 
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluargaPemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
Pemenuhan kebutuhan fisik dan psikologi ibu dan keluarga
 
เฉลยO netวิทย์ชีวะ58
เฉลยO netวิทย์ชีวะ58เฉลยO netวิทย์ชีวะ58
เฉลยO netวิทย์ชีวะ58
 
Acropora cervicornis
Acropora  cervicornisAcropora  cervicornis
Acropora cervicornis
 
G biology bio2
G biology bio2G biology bio2
G biology bio2
 
สืบพันธุ์
สืบพันธุ์สืบพันธุ์
สืบพันธุ์
 

Similar to Itb 2021 - Bulding Quick APIs by Gavin Pickin

Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
Amazon Web Services
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's
Ortus Solutions, Corp
 
Crafting APIs
Crafting APIsCrafting APIs
Crafting APIs
Tatiana Al-Chueyr
 
API Workshop: Deep dive into REST APIs
API Workshop: Deep dive into REST APIsAPI Workshop: Deep dive into REST APIs
API Workshop: Deep dive into REST APIs
Tom Johnson
 
Azure APIM Presentation to understand about.pptx
Azure APIM Presentation to understand about.pptxAzure APIM Presentation to understand about.pptx
Azure APIM Presentation to understand about.pptx
pythagorus143
 
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
AWS Chicago
 
Introduction to google endpoints
Introduction to google endpointsIntroduction to google endpoints
Introduction to google endpoints
Shinto Anto
 
Releasing Software Quickly and Reliably with AWS CodePipline
Releasing Software Quickly and Reliably with AWS CodePiplineReleasing Software Quickly and Reliably with AWS CodePipline
Releasing Software Quickly and Reliably with AWS CodePipline
Amazon Web Services
 
Managing the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS LambdaManaging the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS Lambda
Amazon Web Services
 
Devoxx 2018 - Pivotal and AxonIQ - Quickstart your event driven architecture
Devoxx 2018 -  Pivotal and AxonIQ - Quickstart your event driven architectureDevoxx 2018 -  Pivotal and AxonIQ - Quickstart your event driven architecture
Devoxx 2018 - Pivotal and AxonIQ - Quickstart your event driven architecture
Ben Wilcock
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsug
Toshiaki Maki
 
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
FDConf
 
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar SeriesContinuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
Amazon Web Services
 
Application Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless WorldApplication Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless World
Amazon Web Services
 
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure FunctionsSharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
Sébastien Levert
 
2014 SharePoint Saturday Melbourne Apps or not to Apps
2014 SharePoint Saturday Melbourne Apps or not to Apps2014 SharePoint Saturday Melbourne Apps or not to Apps
2014 SharePoint Saturday Melbourne Apps or not to Apps
Gilles Pommier
 
Migrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
Migrate your Existing Express Apps to AWS Lambda and Amazon API GatewayMigrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
Migrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
Amazon Web Services
 
I Love APIs - Oct 2015
I Love APIs - Oct 2015I Love APIs - Oct 2015
I Love APIs - Oct 2015
Mike McNeil
 
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Amazon Web Services
 

Similar to Itb 2021 - Bulding Quick APIs by Gavin Pickin (20)

Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
Releasing Software Quickly and Reliably With AWS CodePipeline by Mark Mansour...
 
Into The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api'sInto The Box | Alexa and ColdBox Api's
Into The Box | Alexa and ColdBox Api's
 
Crafting APIs
Crafting APIsCrafting APIs
Crafting APIs
 
API Workshop: Deep dive into REST APIs
API Workshop: Deep dive into REST APIsAPI Workshop: Deep dive into REST APIs
API Workshop: Deep dive into REST APIs
 
Azure APIM Presentation to understand about.pptx
Azure APIM Presentation to understand about.pptxAzure APIM Presentation to understand about.pptx
Azure APIM Presentation to understand about.pptx
 
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
Serverless Framework Workshop - Tyler Hendrickson, Chicago/burbs
 
Introduction to google endpoints
Introduction to google endpointsIntroduction to google endpoints
Introduction to google endpoints
 
Releasing Software Quickly and Reliably with AWS CodePipline
Releasing Software Quickly and Reliably with AWS CodePiplineReleasing Software Quickly and Reliably with AWS CodePipline
Releasing Software Quickly and Reliably with AWS CodePipline
 
Managing the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS LambdaManaging the Continuous Delivery of Code to AWS Lambda
Managing the Continuous Delivery of Code to AWS Lambda
 
Devoxx 2018 - Pivotal and AxonIQ - Quickstart your event driven architecture
Devoxx 2018 -  Pivotal and AxonIQ - Quickstart your event driven architectureDevoxx 2018 -  Pivotal and AxonIQ - Quickstart your event driven architecture
Devoxx 2018 - Pivotal and AxonIQ - Quickstart your event driven architecture
 
Spring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsugSpring Cloud Function & Project riff #jsug
Spring Cloud Function & Project riff #jsug
 
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
MongoDB World 2018: Tutorial - Got Dibs? Building a Real-Time Bidding App wit...
 
"Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native ""Service Worker: Let Your Web App Feel Like a Native "
"Service Worker: Let Your Web App Feel Like a Native "
 
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar SeriesContinuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
Continuous Delivery with AWS Lambda - AWS April 2016 Webinar Series
 
Application Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless WorldApplication Lifecycle Management in a Serverless World
Application Lifecycle Management in a Serverless World
 
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure FunctionsSharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
SharePoint Fest Seattle - SharePoint Framework, Angular & Azure Functions
 
2014 SharePoint Saturday Melbourne Apps or not to Apps
2014 SharePoint Saturday Melbourne Apps or not to Apps2014 SharePoint Saturday Melbourne Apps or not to Apps
2014 SharePoint Saturday Melbourne Apps or not to Apps
 
Migrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
Migrate your Existing Express Apps to AWS Lambda and Amazon API GatewayMigrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
Migrate your Existing Express Apps to AWS Lambda and Amazon API Gateway
 
I Love APIs - Oct 2015
I Love APIs - Oct 2015I Love APIs - Oct 2015
I Love APIs - Oct 2015
 
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
Integrating Infrastructure as Code into a Continuous Delivery Pipeline | AWS ...
 

More from Gavin Pickin

Containerizing ContentBox CMS
Containerizing ContentBox CMSContainerizing ContentBox CMS
Containerizing ContentBox CMS
Gavin Pickin
 
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
Gavin Pickin
 
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLEAN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
Gavin Pickin
 
3 WAYS TO TEST YOUR COLDFUSION API
3 WAYS TO TEST YOUR COLDFUSION API3 WAYS TO TEST YOUR COLDFUSION API
3 WAYS TO TEST YOUR COLDFUSION API
Gavin Pickin
 
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
Gavin Pickin
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
Gavin Pickin
 
BDD Testing and Automating from the trenches - Presented at Into The Box June...
BDD Testing and Automating from the trenches - Presented at Into The Box June...BDD Testing and Automating from the trenches - Presented at Into The Box June...
BDD Testing and Automating from the trenches - Presented at Into The Box June...
Gavin Pickin
 
How do I write Testable Javascript so I can Test my CF API on Server and Client
How do I write Testable Javascript so I can Test my CF API on Server and ClientHow do I write Testable Javascript so I can Test my CF API on Server and Client
How do I write Testable Javascript so I can Test my CF API on Server and Client
Gavin Pickin
 
Just Mock It - Mocks and Stubs
Just Mock It - Mocks and StubsJust Mock It - Mocks and Stubs
Just Mock It - Mocks and Stubs
Gavin Pickin
 
How do I write Testable Javascript?
How do I write Testable Javascript?How do I write Testable Javascript?
How do I write Testable Javascript?
Gavin Pickin
 
Getting your Hooks into Cordova
Getting your Hooks into CordovaGetting your Hooks into Cordova
Getting your Hooks into Cordova
Gavin Pickin
 
Setting up your Multi Engine Environment - Apache Railo and ColdFusion
Setting up your Multi Engine Environment - Apache Railo and ColdFusionSetting up your Multi Engine Environment - Apache Railo and ColdFusion
Setting up your Multi Engine Environment - Apache Railo and ColdFusion
Gavin Pickin
 

More from Gavin Pickin (12)

Containerizing ContentBox CMS
Containerizing ContentBox CMSContainerizing ContentBox CMS
Containerizing ContentBox CMS
 
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
ColdBox APIs + VueJS - powering Mobile, Desktop and Web Apps with 1 VueJS cod...
 
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLEAN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
AN EXERCISE IN CLEANER CODE - FROM LEGACY TO MAINTAINABLE
 
3 WAYS TO TEST YOUR COLDFUSION API
3 WAYS TO TEST YOUR COLDFUSION API3 WAYS TO TEST YOUR COLDFUSION API
3 WAYS TO TEST YOUR COLDFUSION API
 
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
Take home your very own free Vagrant CFML Dev Environment - Presented at dev....
 
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
How do I write Testable Javascript - Presented at dev.Objective() June 16, 2016
 
BDD Testing and Automating from the trenches - Presented at Into The Box June...
BDD Testing and Automating from the trenches - Presented at Into The Box June...BDD Testing and Automating from the trenches - Presented at Into The Box June...
BDD Testing and Automating from the trenches - Presented at Into The Box June...
 
How do I write Testable Javascript so I can Test my CF API on Server and Client
How do I write Testable Javascript so I can Test my CF API on Server and ClientHow do I write Testable Javascript so I can Test my CF API on Server and Client
How do I write Testable Javascript so I can Test my CF API on Server and Client
 
Just Mock It - Mocks and Stubs
Just Mock It - Mocks and StubsJust Mock It - Mocks and Stubs
Just Mock It - Mocks and Stubs
 
How do I write Testable Javascript?
How do I write Testable Javascript?How do I write Testable Javascript?
How do I write Testable Javascript?
 
Getting your Hooks into Cordova
Getting your Hooks into CordovaGetting your Hooks into Cordova
Getting your Hooks into Cordova
 
Setting up your Multi Engine Environment - Apache Railo and ColdFusion
Setting up your Multi Engine Environment - Apache Railo and ColdFusionSetting up your Multi Engine Environment - Apache Railo and ColdFusion
Setting up your Multi Engine Environment - Apache Railo and ColdFusion
 

Recently uploaded

UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
DianaGray10
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
Frank van Harmelen
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
DanBrown980551
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
Alan Dix
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Inflectra
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Ramesh Iyer
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
Product School
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
Elena Simperl
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
BookNet Canada
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Product School
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
Cheryl Hung
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
CatarinaPereira64715
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
Product School
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
Prayukth K V
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
Thijs Feryn
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Thierry Lestable
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Jeffrey Haguewood
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
Abida Shariff
 

Recently uploaded (20)

UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4UiPath Test Automation using UiPath Test Suite series, part 4
UiPath Test Automation using UiPath Test Suite series, part 4
 
Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*Neuro-symbolic is not enough, we need neuro-*semantic*
Neuro-symbolic is not enough, we need neuro-*semantic*
 
FIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdfFIDO Alliance Osaka Seminar: Overview.pdf
FIDO Alliance Osaka Seminar: Overview.pdf
 
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdfFIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
FIDO Alliance Osaka Seminar: Passkeys and the Road Ahead.pdf
 
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
LF Energy Webinar: Electrical Grid Modelling and Simulation Through PowSyBl -...
 
Epistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI supportEpistemic Interaction - tuning interfaces to provide information for AI support
Epistemic Interaction - tuning interfaces to provide information for AI support
 
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered QualitySoftware Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
Software Delivery At the Speed of AI: Inflectra Invests In AI-Powered Quality
 
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
Builder.ai Founder Sachin Dev Duggal's Strategic Approach to Create an Innova...
 
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
AI for Every Business: Unlocking Your Product's Universal Potential by VP of ...
 
When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...When stars align: studies in data quality, knowledge graphs, and machine lear...
When stars align: studies in data quality, knowledge graphs, and machine lear...
 
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...Transcript: Selling digital books in 2024: Insights from industry leaders - T...
Transcript: Selling digital books in 2024: Insights from industry leaders - T...
 
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
Unsubscribed: Combat Subscription Fatigue With a Membership Mentality by Head...
 
Key Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdfKey Trends Shaping the Future of Infrastructure.pdf
Key Trends Shaping the Future of Infrastructure.pdf
 
ODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User GroupODC, Data Fabric and Architecture User Group
ODC, Data Fabric and Architecture User Group
 
How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...How world-class product teams are winning in the AI era by CEO and Founder, P...
How world-class product teams are winning in the AI era by CEO and Founder, P...
 
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 previewState of ICS and IoT Cyber Threat Landscape Report 2024 preview
State of ICS and IoT Cyber Threat Landscape Report 2024 preview
 
Accelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish CachingAccelerate your Kubernetes clusters with Varnish Caching
Accelerate your Kubernetes clusters with Varnish Caching
 
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
Empowering NextGen Mobility via Large Action Model Infrastructure (LAMI): pav...
 
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
Slack (or Teams) Automation for Bonterra Impact Management (fka Social Soluti...
 
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptxIOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
IOS-PENTESTING-BEGINNERS-PRACTICAL-GUIDE-.pptx
 

Itb 2021 - Bulding Quick APIs by Gavin Pickin

  • 1. Building Quick APIs by Gavin Pickin https://github.com/gpickin/itb2021-building-quick-apis
  • 2. Building Quick APIs by Gavin Pickin https://github.com/gpickin/itb2021-building-quick-apis
  • 3.
  • 4. Gavin Pickin Who am I? • Software Consultant for Ortus Solutions • Work with ColdBox, CommandBox, ContentBox APIs and VueJS every day! • Working with Coldfusion for 22 years • Working with Javascript just as long • Love learning and sharing the lessons learned • From New Zealand, live in Bakersfield, Ca • Loving wife, lots of kids, and countless critters @gpickin
  • 5. What is this talk? We will setup a secure API using fluent query language - and you’ll see how quick Quick development can be! We will use ● ColdBox ● ColdBox’s built in REST BaseHandler ● Route Visualizer ● CBSecurity ● Quick ORM
  • 6. What is this talk not? ● We will not be adding an API to a Legacy Site ● We will not be adding an API to a non ColdBox site ● It is not my CF Meetup Talk “Building APIs with ColdFusion Part 1” https://www.youtube.com/watch?v=UdgRt8HIKD0 BUT YOU COULD DO ALL OF THESE THINGS WITH THE KNOWLEDGE FROM THIS TALK
  • 7. Why should I give this talk? • I build a lot of APIs for Customers • I have seen many different ways to build an API • I’m going to share some of the lessons I have learned. • I try to present in step by step follow along later format that I think you’ll love • Hopefully you’ll learn something • Hopefully it will be useful.
  • 8. What is an API? API is an application programming interface More commonly when someone says API today they think of an JSON API, usually we hope for a REST API but not always. APIs can be xml, soap, but it’s very common to talk about JSON apis, and that’s what we’re talking about today. Although most of it is relatable.
  • 9. REST JSON API vs JSON API What is REST REST is acronym for REpresentational State Transfer. It is architectural style for distributed hypermedia systems and was first presented by Roy Fielding in 2000 in his famous dissertation. All REST are APIs but not all APIs are REST.
  • 10. Guiding Principles of REST ● Client–server ● Stateless ● Cacheable ● Uniform interface ● Layered system The key abstraction of information in REST is a resource. Any information that can be named can be a resource: a document or image, a temporal service, a collection of other resources, a non-virtual object (e.g. a person), and so on. REST uses a resource identifier to identify the particular resource involved in an interaction between components.
  • 11. What App are we working on? SOAPBOX API - An API for a twitter clone we built for our ColdBox Zero to Hero Training.
  • 12. Let’s do this!!! Start up CommandBox!!!
  • 13. Create a ColdBox App box coldbox create app soapbox-api This installs: ● ColdBox ● TestBox ● CommandBox-dotEnv ● CommandBox-cfconfig ● CommandBox-cfformat
  • 14. Let’s update our .env ● Change the connection string to match our DB - soapboxapi ● Change the DB_DATABASE to match our DB - soapboxapi ● Change ports, user name and password to match
  • 15. Let’s start our server That port matches the testbox runner in the box.json http://127.0.0.1:53163/ - our site http://127.0.0.1:53163/tests/runner.cfm - our tests box start port=53163
  • 16. Let’s plan our API What is an Example URL - /api/v01/users We’re going to make API a module with a V01 module inside of it. ● Add modules_app folder for this apps custom modules ● Add modules_app/api folder with ModuleConfig.cfc ● Add modules_app/api/modules/api-v01 folder with ModuleConfig.cfc API - V01
  • 17. Let’s build out our API V01 Module ● Add modules_app/api/modules/api-v01/config Folder with Router.cfc ● Setup the base route of “/” to go to main.index ● Add api-v01/handlers/main.cfc which extends coldbox.system.RestHandler ● Add index event in the main handler ● Index event should sets data in the response object to welcome the user to the api. http://127.0.0.1:53163/api/v01 API - V01
  • 18. Let’s plan our API USER resource GET /api/v02/users - get a list of users POST /api/v02/users - create a new user GET /api/v02/users/:userID - get a single user POST /api/v02/users/:userID - update a single user DELETE /api/v02/users/:userID - delete a single user API - V02
  • 19. Add User Resource to Router.cfc resources( resource = "users", handler = "users", parameterName = "userID", only = [ "index", "show", "create", "update", "delete" ] ); API - V02
  • 20. Let’s view our Routes box install route-visualizer API - V02
  • 21. Build our Users Handler function index( event, rc, prc ){ event.getResponse().setData( "List Users" ); } function create( event, rc, prc ){ event.getResponse().setData( "Create User" ); } API - V02 http://127.0.0.1:53163/api/v02/users
  • 22. Secure our CUD Actions Let’s use CBSecurity to lock down our non READ functionality ● CREATE ● UPDATE ● DELETE API - V03
  • 23. Install CBSecurity Add the Config to your config/ColdBox.cfc Add a JWT Secret incase .env has a blank one Add “api-v03:main.index” for “invalidAuthenticationEvent” Add “api-v03:main.index” for “invalidAuthorizationEvent” API - V03 box install cbsecurity
  • 24. Add Secured Metadata function create( event, rc, prc ) secured{ event.getResponse().setData( "Create Users" ); } API - V03
  • 26. Updating Redirects for API Authentication and Authorization Issues You should really setup your main ColdBox app for an HTML page and your API module for an API page Add settings to the API-v04 Module Config Add “api-v04:main.index” for “invalidAuthenticationEvent” Add “api-v04:main.index” for “invalidAuthorizationEvent” API - V04
  • 27. Updating Redirects for API Authentication and Authorization Issues http://127.0.0.1:53163/api/v04/users/?_method=post Now we are redirected to an API Handler You can add new methods for onInvalidAuth and or onInvalidAuthorization to be more specific in your responses API - V04
  • 28. Install and Configure Quick add a datasource definition in Application.cfc API - V05 this.datasource = "soapboxapi"; box install quick
  • 29. Create our Quick User Entity component extends="quick.models.BaseEntity" accessors="true" { property name="id" type="string"; property name="username" type="string"; property name="email" type="string"; property name="password" type="string"; } API - V05
  • 30. Quick is Smart ● Quick guesses the table is named Users because the entity is User ● Quick guesses the Primary Key is ID ● Quick uses the Datasource defined in the Application.cfc ● Quick can make a Virtual Service for us from a WireBox Injection property name="userService" inject="quickService:User@api-v05"; Quick does a lot for us API - V05
  • 31. Show a User function show( event, rc, prc ){ event.paramValue( "userID", 0 ); event.getResponse().setData( userService .findOrFail( rc.userID ) .getMemento() ); } API - V05
  • 33. What if we can’t find that User? http://127.0.0.1:53163/api/v05/users/x 404 response API - V05
  • 34. Return a list of Users function index( event, rc, prc ){ event.getResponse().setData( userService .asMemento() .get() ); } API - V06
  • 35. What is asMemento() asMemento() is a special function that tells quick you want to map over all of the objects in the array, and call getMemento() on all of the items .get().getMemento() doesn’t work because .get() returns an array As memento is essentially the following done for you. ...get().map( (item) => { return item.getMemento() } ); API - V06
  • 36. Reinit and check the API http://127.0.0.1:53163/api/v06/users/ API - V06
  • 37. Configuring Mementifier ● We don’t want to return all of the fields ● For example Password, even if it is encrypted https://github.com/coldbox-modules/mementifier API - V07
  • 38. Mementifier Inline Excludes API - V07 userService .asMemento( excludes=[ "password" ] ) .get() http://127.0.0.1:53163/api/v07/users
  • 39. Mementifier - Inline Includes API - V08 userService .asMemento( includes=[ "id", "username", "email" ], ignoreDefaults = true ) .get() http://127.0.0.1:53163/api/v08/users
  • 40. Mementifier - Entity Config API - V09 //models/User.cfc this.memento = { defaultIncludes=[ "username", "email" ], neverInclude=["password"] } http://127.0.0.1:53163/api/v09/users/2
  • 41. Mementifier - Inline Includes API - V10 function index( event, rc, prc ){ event.getResponse().setData( userService .asMemento( includes=[ “ID” ] ) .get() ); } http://127.0.0.1:53163/api/v10/users/
  • 42. Using Where to Filter Users API - V11 event.paramValue( "username_filter", "" ); event.getResponse().setData( userService .where( "username", "like", '%#rc.username_filter#%') .asMemento( includes="ID" ) .get() ); http://127.0.0.1:53163/api/v11/users?username_filter=gp
  • 43. Using Scope to Filter Users API - V12 //handler - use this userService.whereUsernameLike(rc.username_filter) // not this userService.where( "username", "like", '%#rc.username_filter#%') // models/User.cfc function scopeWhereUsernameLike( qb, filter ){ qb.where( "Username", "like", '%#filter#%' ) } http://127.0.0.1:53163/api/v12/users?username_filter=gp
  • 44. Using Dynamic Where to Match Users API - V13 userService .whereUsernameLike(rc.username_filter) .whereUsername(rc.username) .asMemento( includes="ID" ) .get() http://127.0.0.1:53163/api/v13/users?username_filter=gp
  • 45. Using When for Empty Variables API - V14 userService .whereUsernameLike(rc.username_filter) .when( len( rc.username ), function( q ) { q.whereUsername(rc.username) } .asMemento( includes="ID" ) .get() http://127.0.0.1:53163/api/v14/users?username_filter=gp
  • 46. Using When for Empty Variables API - V14 userService .whereUsernameLike(rc.username_filter) .when( len( rc.username ), function( q ) { q.whereUsername(rc.username) } .asMemento( includes="ID" ) .get() http://127.0.0.1:53163/api/v14/users?username=gp
  • 47. Using When for Empty Variables API - V14 userService .whereUsernameLike(rc.username_filter) .when( len( rc.username ), function( q ) { q.whereUsername(rc.username) } .asMemento( includes="ID" ) .get() http://127.0.0.1:53163/api/v14/users?username=gpickin
  • 48. Using ‘Or’ for Similar Filters API - V15 userService .whereUsernameLike(rc.username_filter) .when( len( rc.username ), function( q ) { q.whereUsername(rc.username) } .asMemento( includes="ID" ) .get() http://127.0.0.1:53163/api/v14/users?username=gpickin&username_filter=luis
  • 49. Using ‘Or’ for Similar Filters API - V15 userService .whereUsernameLike(rc.username_filter) .orWhere( function(q){ q.when( len( rc.username ), function( q2 ) { q2.orwhereUsername(rc.username) }) }) http://127.0.0.1:53163/api/v14/users?username=gpickin&username_filter=lui
  • 50. Setup Rant Resource API - V16 resources( resource = "rants", handler = "rants", parameterName = "rantID", only = [ "index", "show", "create", "update", "delete" ] );
  • 51. Setup Rant Handler API - V16 /** * Manage Rants API Handler * */ component extends="coldbox.system.RestHandler "{ /** * Display a list of Rants */ function index( event, rc, prc ){ event.getResponse().setData( "Show Rants"); } /** * Create a Rant */
  • 52. Test Rant Resource API - V16 http://127.0.0.1:53163/api/v16/rants? http://127.0.0.1:53163/api/v16/rants/6
  • 53. Create Rant Entity API - V17 component extends="quick.models.BaseEntity" accessors="true" { property name="id" type="string"; property name="body" type="string"; property name="createdDate" type="date"; property name="modifiedDate" type="date"; property name="userID" type="string"; }
  • 54. Inject Rant Service and Return Rants API - V17 property name="rantService" inject="quickService:Rant@api-v17"; function index( event, rc, prc ){ event.getResponse().setData( rantService .asMemento() .get() ); } http://127.0.0.1:53163/api/v17/rants
  • 55. Paginate the Rants Returned API - V18 http://127.0.0.1:53163/api/v17/rants ● We don’t want to return every record, it will only grow longer and longer over time, and performance will suffer ● ColdBox RESTBaseHandler already has Pagination information ● Let’s use Quick’s Paginate function
  • 56. Paginate the Rants Returned API - V18 http://127.0.0.1:53163/api/v18/rants event.getResponse().setData( rantService .asMemento() .paginate(1,10) );
  • 57. Paginate the Rants Returned API - V18 http://127.0.0.1:53163/api/v18/rants event.getResponse().setData( rantService .asMemento() .paginate(1,10) ); Why do we have 2 sets of Pagination Data???
  • 58. Use SetDataWithPagination API - V19 http://127.0.0.1:53163/api/v19/rants event .getResponse() .setDataWithPagination( rantService .asMemento() .paginate(1,10) );
  • 59. Return Rants User Information // Add User Relationship to Rant.cfc function user(){ return hasOne( "User@api-v20", "id", "userID" ); } API - V20 // Update Rants.cfc handler event.getResponse().setDataWithPagination( rantService .asMemento( includes="user" ) .paginate(1,10) );
  • 60. Return Rants User Information API - V20 http://127.0.0.1:53163/api/v20/rants
  • 61. Return Rants User Information API - V20 ● Nested Fields ● What if we just want 1 field? ● How is Mementifier getting the data?? http://127.0.0.1:53163/api/v20/rants
  • 62. Return Rants with SubSelect User Information API - V21 event.getResponse().setDataWithPagination( rantService .addSubselect( "username", "user.username") .asMemento() .paginate(1,10) ); http://127.0.0.1:53163/api/v21/rants
  • 63. Return a Count of Rants for Users API - V22 // Add Rants Relationship to models/User.cfc function rants(){ return hasMany( "Rant@api-v22", "userID", "id" ); } // Update users.cfc handler userService .withCount( "rants" ) .asMemento( includes=["ID","rantsCount"] ) .get() http://127.0.0.1:53163/api/v22/users
  • 64. Return Recent Rants for Users API - V23 //Router.cfc get( "/users/:userID/rants" , "userRants.index" ); // Handlers/userRants.cfc function index( event, rc, prc ){ event.paramValue( "userID", "" ); event.paramValue( "page", 1 ); event.paramValue( "per_page", 10 ); event.getResponse().setDataWithPagination ( rantService .where( "userID", rc.userID ) .orderBy( "createdDate", "desc" ) .asMemento() .paginate( rc.page, rc.per_page ) ); } http://127.0.0.1:53163/api/v23/users/2/rants
  • 65. Create a new Rant API - V24 http://127.0.0.1:53163/api/v24/rants?_method=post&userID=2&body=Adding%20a%20Rant function create( event, rc, prc ){ event.paramValue( "userID", "" ); event.paramValue( "body", "" ); userService .findOrFail( rc.userID ) .rants() .create( { body: rc.body } ); event.getResponse().setData( "Rant Created" ); }
  • 66. View the new Rant API - V24 http://127.0.0.1:53163/api/v24/users/2/rants
  • 67. What if we add an Empty Rant API - V24 http://127.0.0.1:53163/api/v24/rants?_method=post&userID=2&body= Not User Friendly
  • 68. Validate a new Rant API - V25 box Install cbvalidation
  • 69. Validate a new Rant - Handler Constraints API - V25 var validationResult = validate( target = rc, constraints = { body : { required : true } } ) if ( !validationResult.hasErrors() ) { // Normal API Response } else { event.getResponse() .setError( true ) .addMessage( validationResult.getAllErrors() ) .setStatusCode( 400 ) .setStatusText( "Validation error" ); } http://127.0.0.1:53163/api/v25/rants?_method=post&userID=2&body=
  • 70. Validate a new Rant - Entity Constraints API - V26 //Rant.cfc this.constraints = { body : { required : true }, userID: { required : true, type : "numeric" } }; // Handler/rants.cfc var rant = getInstance( "Rant@api-v26" ) .fill({ body: rc.body, userID: rc.userID }); validateOrFail( rant ); var user = userService.findOrFail( rc.userID ); rant.save(); event.getResponse().setData( "Rant Created" );
  • 71. Validate a new Rant - Entity Constraints API - V26 http://127.0.0.1:53163/api/v26/rants?_method=post&userID=2&body= Body is missing or empty
  • 72. Validate a new Rant - Entity Constraints API - V26 http://127.0.0.1:53163/api/v26/rants?_method=post&userID=xxx&body=MyRant UserID is not numeric
  • 73. Validate a new Rant - Entity Constraints API - V26 http://127.0.0.1:53163/api/v26/rants?_method=post&userID=0&body=MyRant UserID is numeric but not in User table
  • 74. Edit a Rant API - V27 event.paramValue( "rantID", 0 ); event.paramValue( "body", "" ); var rant = rantService.findOrFail( rc.rantID ) .fill({ body: rc.body }); validateOrFail( rant ); rant.save(); event.getResponse().setData( "Rant Updated" );
  • 75. Edit a Rant - Success API - V27 http://127.0.0.1:53163/api/v27/rants/178/?_method=put&body=Yes%20thats%20is%20right
  • 76. Edit a Rant - Missing Body API - V27 http://127.0.0.1:53163/api/v27/rants/178/?_method=put&body=
  • 77. Delete a Rant API - V28 function delete( event, rc, prc ){ event.paramValue( "rantID", 0 ); var rant = rantService.findOrFail( rc.rantID ).delete(); event.getResponse().setData( "Delete a Rant" ); }
  • 78. Delete a Rant that doesn’t Exist API - V28 http://127.0.0.1:53163/api/v28/rants/70000/?_method=delete
  • 79. Delete a Rant that does Exist API - V28 http://127.0.0.1:53163/api/v28/rants/7/?_method=delete
  • 80. Secure the Add / Edit Rant function create( event, rc, prc ) secured{ … } function update( event, rc, prc ) secured{ … } API - V29 NOT LOGGED IN http://127.0.0.1:53163/api/v29/rants/178/?_method=put&body=hiya
  • 81. Secure the Delete Rant with a Special Permission API - V29 function delete( event, rc, prc ) secured="RANT__DELETE"{ … } http://127.0.0.1:53163/api/v29/rants/7/?_method=delete NOT LOGGED IN
  • 82. Create a Generate JWT Endpoint //Router.cfc post( "/login", "session.create" ); delete( "/logout", "session.delete" ); //handlers/session.cfc function create( event, rc, prc ){ token = jwtAuth().fromuser( userService.findOrFail( 2 ) ); event.getResponse() .addMessage( "Token Created" ) .setData( token ); } function delete( event, rc, prc ){ jwtAuth().logout(); event.getResponse().setData( "Delete Session - Log Out" ); } API - V30
  • 83. Decorate User.cfc Entity for JWT API - V30 /** * A struct of custom claims to add to the JWT token */ struct function getJWTCustomClaims(){ return {}; } /** * This function returns an array of all the scopes that should be attached to the JWT * token that will be used for authorization. */ array function getJWTScopes(){ return []; }
  • 84. Hit Generate JWT Endpoint API - V30 http://127.0.0.1:53163/api/v30/login?_method=post
  • 85. Use JWT to Add a Rant API - V30
  • 86. But Wait, there’s more (I wish) I really wanted to show you more, but we don’t have all day. Join me at the CF Online Meetup where I do this again, maybe slower/better Join me for the October Ortus Webinar as we build on top of this. We might make a CFCasts series out of this if you like this style of content
  • 87. You can use images and add them opacity at 90%. This will blend the image with the gradient background. This is a good option for subtitles also. Testing APIs with TestBox with Javier Quintero Up Next
  • 88. E-mail: gavin@ortussolutions.com Twitter: @gpickin Gavin Pickin Senior Software Consultant Ortus Solutions, Corp https://github.com/gpickin/itb2021-building-quick-apis