Exposing Salesforce REST Services using Swagger Visualizing your




































- Slides: 36

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 § 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 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 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 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 any consumer: /account What does the endpoint tell us?

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 @ 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> <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 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. 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; 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. 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. 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. 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

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 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 { //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 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, 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 • 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. 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 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 = "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 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, 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. 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", 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. 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" -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

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
