Exposing Salesforce REST Services using Swagger Visualizing your

  • Slides: 36
Download presentation
Exposing Salesforce REST Services using Swagger Visualizing your REST Services Thys Michels, Lending Club,

Exposing Salesforce REST Services using Swagger Visualizing your REST Services Thys Michels, Lending Club, Software Engineer @thysmichels

Agenda § Objective § Introduction and defining REST endpoints § Force. com REST APIs

Agenda § Objective § Introduction and defining REST endpoints § Force. com REST APIs § Demo REST API § Spring MVC with Swagger Annotations § Demo Spring MVC with Swagger § Resources § Q&A

Objective • Review the basics of REST • Showcase a Force. com REST API

Objective • Review the basics of REST • Showcase a Force. com REST API implementation • Compare different Force. com REST APIs • Develop a Force. com RESTful Service using Swagger

What is REST • REpresentational State Transfer • An architecture style for designing distributed

What is REST • REpresentational State Transfer • An architecture style for designing distributed systems • Not a standard, rather a set of patterns: • Client/Server, Stateless, Uniform interface, etc. • Not tied to HTTP, but associated most commonly with it.

HTTP’s Uniform Interface • URI’s identify resources • HTTP verbs describe a limited set

HTTP’s Uniform Interface • URI’s identify resources • HTTP verbs describe a limited set of operations that can be used to manipulate a resource • GET • DELETE • PUT • POST • Headers help describe the messages

Defining a REST Endpoint What does this endpoint mean to a developer, tester or

Defining a REST Endpoint What does this endpoint mean to a developer, tester or any consumer: /account What does the endpoint tell us?

Defining a REST Endpoint (2) Endpoint Description: Operation Descriptions Input: Parameter Values Form Values

Defining a REST Endpoint (2) Endpoint Description: Operation Descriptions Input: Parameter Values Form Values JSON Format Operations: GET POST PUT DELETE /account Header information Error Codes: Validation Return formats

Salesforce REST APIs • https: //github. com/jesperfj/force-rest-api • Developer: Jesper Joergensen (Product Management @

Salesforce REST APIs • https: //github. com/jesperfj/force-rest-api • Developer: Jesper Joergensen (Product Management @ Heroku) • Lightweight library for building Force. com apps with OAuth authentication and data access through the Force. com REST API. • https: //github. com/ryanbrainard/force-rest-api • Developer: Ryan Brainard • Forked version of Jasper Joergensen project • Caching enhancements • Available in Maven Central

Force. com REST API Maven dependency <repositories> <repository> <id>force-rest-api</id> <name>force-rest-api repository on Git. Hub</name>

Force. com REST API Maven dependency <repositories> <repository> <id>force-rest-api</id> <name>force-rest-api repository on Git. Hub</name> <url>http: //jesperfj. github. com/force-rest-api/repository/</url> </repository> </repositories> <dependency> <group. Id>com. force. api</group. Id> <artifact. Id>force-rest-api</artifact. Id> <version>0. 0. 19</version> </dependency>

Authenticating to Salesforce • Using Username and Password • For backend application where only

Authenticating to Salesforce • Using Username and Password • For backend application where only server authentication is needed: Force. Api api = new Force. Api(new Api. Config(). set. Username("user@domain. com"). set. Password("password+token")); • Using OAuth Username and Password • Front end application where user authentication is needed: Force. Api api = new Force. Api(new Api. Config(). set. Username("user@domain. com"). set. Password("password"). set. Client. Id("longclientidalphanumstring"). set. Client. Secret("notsolongnumeric"));

OAuth Web Server Flow String url = Auth. start. OAuth. Web. Server. Flow(new Authorization.

OAuth Web Server Flow String url = Auth. start. OAuth. Web. Server. Flow(new Authorization. Request(). api. Config(new Api. Config(). set. Client. Id("longclientidalphanumstring"). set. Redirect. URI("https: //myapp. mydomain. com/oauth")). state("mystate")); Api. Session s = Auth. complete. OAuth. Web. Server. Flow(new Authorization. Response(). api. Config(new Api. Config(). set. Client. Id("longclientidalphanumstring"). set. Client. Secret("notsolongnumeric"). set. Redirect. URI("https: //myapp. mydomain. com/oauth")). code("alphanumericstringpassedbackinbrowserrequest")); Force. Api api = new Force. Api(s. get. Api. Config(), s);

Defining your Salesforce POJO Object (Model) import org. codehaus. jackson. annotate. Json. Ignore. Properties;

Defining your Salesforce POJO Object (Model) import org. codehaus. jackson. annotate. Json. Ignore. Properties; import org. codehaus. jackson. annotate. Json. Property; @Json. Ignore. Properties(ignore. Unknown=true) public class Account { @Json. Property(value="Id") String id; @Json. Property(value="Name") String name; }

Force. com REST API Operations • GET: Query a List of SObjects • Query.

Force. com REST API Operations • GET: Query a List of SObjects • Query. Result<Account> res = api. query("SELECT id FROM Account WHERE name LIKE 'Test account%'", Account. class); • GET: Get an SObject • Account res = api. get. SObject("Account", "001 D 000000 INj. Ve"). as(Account. class); • POST: Create a new SObject • Account a = new Account(); a. set. Name("Test account"); String id = api. create. SObject("account", a);

REST API Operations • PUT: Update an SObject when already exist • Account ex.

REST API Operations • PUT: Update an SObject when already exist • Account ex. Account = api. get. SObject("Account", "001 D 000000 INj. Ve"). as(Account. class); api. create. Or. Update. SObject("account", ex. Account); • DELETE: Delete an existing SObject • api. delete. SObject("account”, “ 001 D 000000 INj. Ve”);

Putting it all together import com. force. api. Api. Config; import com. force. api.

Putting it all together import com. force. api. Api. Config; import com. force. api. Force. Api; import com. thysmichels. swagger 4 forcedotcom. models. Account; public class Main { private static final String USERNAME = ”username@email. com"; private static final String PASSWORDTOKEN = ”password+token”; public static void main(String[] args) { Force. Api api = new Force. Api(new Api. Config(). set. Username(USERNAME). set. Password(PASSWORDTOKEN)); Account a = new Account(); a. set. Name("Test account"); String id = api. create. SObject("account", a); a. set. Name("Updated Test Account"); api. update. SObject("account", id, a); Account res = api. get. SObject("Account", id). as(Account. class); api. delete. SObject("account", res. get. Id()); } }

Demo Salesforce REST API Demo

Demo Salesforce REST API Demo

Spring MVC vs Visualforce • The Spring Web model-view-controller (MVC) framework is designed around

Spring MVC vs Visualforce • The Spring Web model-view-controller (MVC) framework is designed around a Dispatcher. Servlet that dispatches requests to: • Model (POJO) • View (JSP) • Controller (@Controller and @Request. Mapping annotation classes) • Visualforce MVC • Model (SObject, Apex Classes) • View resolution (Visualforce Pages/Components) • Controller (Standard or Custom Apex classes)

Spring MVC Architecture

Spring MVC Architecture

Spring MVC OAuth Login Service • XML Annotation. Configuration for setting up Salesforce OAuth:

Spring MVC OAuth Login Service • XML Annotation. Configuration for setting up Salesforce OAuth: <fss: oauth> <fss: oauth. Info endpoint="http: //login. salesforce. com" oauth-key="#{system. Environment['OAUTH_CLIENT_KEY']}" oauth-secret="#{system. Environment['OAUTH_CLIENT_SECRET']}"/> </fss: oauth> • Windows: • Set OAUTH_CLIENT_KEY=3 MVM 3_Gu. VCQ 3 gm. EE 5 al 72 Rm. Bfi. AWh. BX 5 O 2 w. Yc 9 z. TZ 8 • Set OAUTH_CLIENT_SECRET=1319558946720906100 • Unix/Linux • Export OAUTH_CLIENT_KEY=3 MVM 3_Gu. VCQ 3 gm. EE 5 al 72 Rm. Bfi. AWh. BX 5 O 2 w. Yc 9 z. TZ 8 • Export OAUTH_CLIENT_SECRET=1319558946720906100

Salesforce API Spring MVC Controller @Request. Mapping(value = "/api/v 1/account") public class Account. Controller

Salesforce API Spring MVC Controller @Request. Mapping(value = "/api/v 1/account") public class Account. Controller { //Login to salesforce @Autowired Login. Service login. Service; @Request. Mapping(value = "/", method = Request. Method. GET, produces = "application/json") public @Response. Body List<Account> show. All. Accounts() { Query. Result<Account> res = login. Service. get. Force. Api(). query("SELECT Name FROM Account", Account. class); return res. get. Records(); } }

Some Spring MVC Annotations • @Controller - The @Controller annotation indicates that a particular

Some Spring MVC Annotations • @Controller - The @Controller annotation indicates that a particular class serves the role of a controller. • @Request. Mapping – The @Request. Mapping annotation is used to map URLs such as http: //yourwebsiteurl. com/api/v 1/account onto an entire class or a particular handler method. • @Path. Variable – Provides access to URI template variables. • @Request. Param – Provides access to specific Servlet request parameters.

Intro to Swagger • Swagger is a specification and complete framework implementation for describing,

Intro to Swagger • Swagger is a specification and complete framework implementation for describing, producing, consuming, and visualizing RESTful web services. • Company: http: //helloreverb. com/ • Link: https: //developers. helloreverb. com/swagger/ • We will use Swagger to describe, produce, consume and visualize our Force. com REST services.

Swagger Maven Dependency • http: //mvnrepository. com/artifact/com. knappsack/swagger 4 spr ing-web/0. 2. 0 •

Swagger Maven Dependency • http: //mvnrepository. com/artifact/com. knappsack/swagger 4 spr ing-web/0. 2. 0 • Include Maven dependency to you project: <dependency> <group. Id>com. knappsack</group. Id> <artifact. Id>swagger 4 spring-web</artifact. Id> <version>0. 2. 0</version> </dependency>

Swagger Base Controller @Request. Mapping(value = "/api") public class Api. Controller extends Api. Documentation.

Swagger Base Controller @Request. Mapping(value = "/api") public class Api. Controller extends Api. Documentation. Controller { public Api. Controller() { set. Base. Path("https: //force-com-rest-swagger. herokuapp. com"); set. Base. Controller. Package("com. thysmichels. swagger 4 forcedotcom. controllers. api"); set. Base. Model. Package("com. thysmichels. swagger 4 forcedotcom. model"); set. Api. Version("v 1"); } @Request. Mapping(value = "/", method = Request. Method. GET) public String documentation() { return "api"; } }

Swagger Base Controller Annotations • base. Path - optional - the base URL of

Swagger Base Controller Annotations • base. Path - optional - the base URL of your web application, for example https: //forcecom-rest-swagger. herokuapp. com • base. Controller. Package - optional - this is the package you want swagger 4 spring-web to scan to look for classes annotated with @Controller. • base. Model. Package - optional - this is the package you want to scan if all your model objects are in a specific directory. • api. Version - required - this is the version of your API

Swagger Annotations @Api – describe a RESTful Endpoint on a high level @Api(value =

Swagger Annotations @Api – describe a RESTful Endpoint on a high level @Api(value = "Account operations", listing. Class = "Account. Controller", base. Path = "/api/v 1/account", description = "All operations for accounts")

Swagger Annotations @Api. Operation – define a RESTful operation • @Api. Operation(value = ”Get

Swagger Annotations @Api. Operation – define a RESTful operation • @Api. Operation(value = ”Get all accounts", notes = ”Get all account (max: 200) ", http. Method = "GET", response. Class = "Account", multi. Value. Response = true)

Swagger Annotations @Api. Error – define one error code • @Api. Error(code = 500,

Swagger Annotations @Api. Error – define one error code • @Api. Error(code = 500, reason = "Process error") @Api. Errors – define multiple error codes • @Api. Errors(value = { @Api. Error(code = 400, reason = "Invalid Id supplied"), @Api. Error(code = 404, reason = "Account not found") })

Swagger Annotations @Api. Param– define path variables • public @Response. Body Account find. Account.

Swagger Annotations @Api. Param– define path variables • public @Response. Body Account find. Account. By. Id (@Api. Param(internal. Description = "java. lang. string", name = "account. Id", required = true, value = "string”)) {}

Putting it all together @Controller @Request. Mapping(value = "/api/v 1/account") @Api(value = "Account operations",

Putting it all together @Controller @Request. Mapping(value = "/api/v 1/account") @Api(value = "Account operations", listing. Class = "Account. Controller", base. Path = "/api/v 1/account", description = "All operations for accounts") public class Account. Controller { @Autowired Account. Service account. Service; @Api. Operation(value = "Find all accounts", notes = "Get all account currently available", response. Class = "Account", multi. Value. Response = true) @Api. Error(code = 500, reason = "Process error") @Request. Mapping(value = "/", method = Request. Method. GET, produces = "application/json") public @Response. Body List<Account> show. All. Accounts() { return account. Service. list. Accounts(); } } http. Method = "GET",

Swagger Java. Script function display. Swagger. Documents() { var url = '<c: url value="/api/resource.

Swagger Java. Script function display. Swagger. Documents() { var url = '<c: url value="/api/resource. List"/>'; window. swagger. Ui = new Swagger. Ui({ discovery. Url: url, dom_id: "swagger-ui-container", support. Header. Params: false, supported. Submit. Methods: ['get', 'post', 'put', 'delete'], api. Key: "", … }

Invoking REST Endpoint • Using curl • curl -H "Accept: application/json" -H "Content-type: application/json"

Invoking REST Endpoint • Using curl • curl -H "Accept: application/json" -H "Content-type: application/json" -X POST -d '{"name": "New Account Name"}' http: //localhost: 8080/api/v 1/account • Using Java Http. Client client = new Default. Http. Client(); Http. Post post = new Http. Post("http: //localhost: 8080/api/v 1/account"); post. set. Entity(new String. Entity("{"name": "New Account"}")); post. set. Header("Accept", "application/json"); post. set. Header("Content-Type", "application/json"); Http. Response response = client. execute(post);

Force. com REST Services with Swagger Demo

Force. com REST Services with Swagger Demo

Resources • Heroku: Force. com Services using Swagger • https: //force-com-rest-swagger. herokuapp. com/ •

Resources • Heroku: Force. com Services using Swagger • https: //force-com-rest-swagger. herokuapp. com/ • Git. Hub: Repository • https: //github. com/thysmichels/force. com-swagger-rest-spring-mvc • Swagger Sample Projects • https: //github. com/wordnik/swagger-core/tree/master/samples

Thys Michels Software Engineer, @thysmichels

Thys Michels Software Engineer, @thysmichels