Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
What's new
4
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Switch to GitLab Next
Sign in / Register
Toggle navigation
Menu
Open sidebar
John Vester
salesforce-integration-service
Commits
7676e2eb
Commit
7676e2eb
authored
Jun 28, 2021
by
john-vester
Browse files
Additional updates, plus updates
parent
55f7499d
Changes
6
Hide whitespace changes
Inline
Side-by-side
README.md
View file @
7676e2eb
...
...
@@ -56,6 +56,7 @@ For this example, only the `Contact` object in Salesforce will be utilized, whic
```
java
public
class
Contact
{
private
String
id
;
private
String
name
;
private
String
title
;
private
String
department
;
...
...
@@ -71,14 +72,106 @@ public class SalesforceAttributes {
The following URIs exist with this service:
`GET - /contacts`
- returns a list of
`Contacts`
from Salesforce
*
`GET - /contacts`
- returns a list of
`Contact`
objects from the connected Salesforce instance
*
`GET - /contacts/{id}`
- returns a single
`Contact`
object for the provided
`id`
from the connected Salesforce instance
*
`PATCH - /contacts/{id}`
- performs the necessary updates and returns the updated object for the following
`PatchUpdates`
object:
`PATCH - /contacts/{id}`
- performs the necessary updates and returns the updated object
```
java
public
class
PatchUpdates
extends
HashMap
<
String
,
String
>
{
}
```
### GET Contacts
Below, is an example of a
`GET`
request to retrieve all
`Contact`
objects in Salesforce:
```
shell
curl
--location
--request
GET
'http://localhost:9999/contacts'
```
An HTTP
`200`
(OK) response will be returned, along with a full list of
`Contact`
entries:
```
json
[
{
"attributes"
:
{
"type"
:
"Contact"
,
"url"
:
"/services/data/v52.0/sobjects/Contact/0035e000008eXq0AAE"
},
"id"
:
"0035e000008eXq0AAE"
,
"Name"
:
"Rose Gonzalez"
,
"Title"
:
"SVP, Procurement"
,
"Department"
:
"Procurement"
},
//
additional
items
here
{
"attributes"
:
{
"type"
:
"Contact"
,
"url"
:
"/services/data/v52.0/sobjects/Contact/0035e000008eXqJAAU"
},
"id"
:
"0035e000008eXqJAAU"
,
"Name"
:
"Jake Llorrac"
,
"Title"
:
null
,
"Department"
:
null
}
]
```
### GET Single Contact
Below, is an example of
`GET`
request for a single
`Contact`
(using values from the list above):
```
shell
curl
--location
--request
GET
'http://localhost:9999/contacts/0035e000008eXq0AAE'
```
An HTTP
`200`
(OK) response will be returned, along with the requested
`Contact`
entry:
```
json
{
"attributes"
:
{
"type"
:
"Contact"
,
"url"
:
"/services/data/v52.0/sobjects/Contact/0035e000008eXq0AAE"
},
"id"
:
"0035e000008eXq0AAE"
,
"Name"
:
"Rose Gonzalez"
,
"Title"
:
"SVP, Procurement"
,
"Department"
:
"Procurement"
}
```
### PATCH Contact
Below, is an example of a
`PATCH`
request using cURL:
```
shell
curl
--location
--request
PATCH
'http://localhost:9999/contacts/0035e000008eXq0AAE'
\
--header
'Content-Type: application/json'
\
--data-raw
'{
"Title": "SVP, Procurement 2"
}'
```
An HTTP
`202`
(Accepted) response will be returned, along with the updated
`Contact`
entry:
```
json
{
"attributes"
:
{
"type"
:
"Contact"
,
"url"
:
"/services/data/v52.0/sobjects/Contact/0035e000008eXq0AAE"
},
"id"
:
"0035e000008eXq0AAE"
,
"Name"
:
"Rose Gonzalez"
,
"Title"
:
"SVP, Procurement 2"
,
"Department"
:
"Procurement"
}
```
## Caching
This repository employs the very basic
`spring-boot-starter-cache`
in order to reduce the need to make API calls to Salesforce.
To keep things simple, when the
`PATCH`
URI (noted above) is called, the entire cache will be evicted.
## Additional Information
...
...
pom.xml
View file @
7676e2eb
...
...
@@ -34,6 +34,16 @@
<artifactId>
httpclient
</artifactId>
<version>
4.5.13
</version>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-lang3
</artifactId>
<version>
3.12.0
</version>
</dependency>
<dependency>
<groupId>
org.apache.commons
</groupId>
<artifactId>
commons-collections4
</artifactId>
<version>
4.4
</version>
</dependency>
<dependency>
<groupId>
org.springframework.boot
</groupId>
...
...
src/main/java/com/gitlab/johnjvester/salesforceintegrationservice/controllers/ContactController.java
View file @
7676e2eb
package
com.gitlab.johnjvester.salesforceintegrationservice.controllers
;
import
com.gitlab.johnjvester.salesforceintegrationservice.models.Contact
;
import
com.gitlab.johnjvester.salesforceintegrationservice.models.PatchUpdates
;
import
com.gitlab.johnjvester.salesforceintegrationservice.services.ContactService
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
...
...
@@ -9,6 +10,9 @@ import org.springframework.http.MediaType;
import
org.springframework.http.ResponseEntity
;
import
org.springframework.web.bind.annotation.CrossOrigin
;
import
org.springframework.web.bind.annotation.GetMapping
;
import
org.springframework.web.bind.annotation.PatchMapping
;
import
org.springframework.web.bind.annotation.PathVariable
;
import
org.springframework.web.bind.annotation.RequestBody
;
import
org.springframework.web.bind.annotation.RequestMapping
;
import
org.springframework.web.bind.annotation.RestController
;
...
...
@@ -31,4 +35,24 @@ public class ContactController {
return
new
ResponseEntity
<>(
HttpStatus
.
BAD_REQUEST
);
}
}
@GetMapping
(
value
=
"/contacts/{id}"
)
public
ResponseEntity
<
Contact
>
getContacts
(
@PathVariable
String
id
)
{
try
{
return
new
ResponseEntity
<>(
contactService
.
getContact
(
id
),
HttpStatus
.
OK
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
new
ResponseEntity
<>(
HttpStatus
.
BAD_REQUEST
);
}
}
@PatchMapping
(
value
=
"/contacts/{id}"
)
public
ResponseEntity
<
Contact
>
updateContact
(
@PathVariable
String
id
,
@RequestBody
PatchUpdates
patchUpdates
)
{
try
{
return
new
ResponseEntity
<>(
contactService
.
updateContact
(
id
,
patchUpdates
),
HttpStatus
.
ACCEPTED
);
}
catch
(
Exception
e
)
{
log
.
error
(
e
.
getMessage
(),
e
);
return
new
ResponseEntity
<>(
HttpStatus
.
BAD_REQUEST
);
}
}
}
src/main/java/com/gitlab/johnjvester/salesforceintegrationservice/models/Contact.java
View file @
7676e2eb
...
...
@@ -5,6 +5,7 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import
lombok.AllArgsConstructor
;
import
lombok.Data
;
import
lombok.NoArgsConstructor
;
import
org.apache.commons.lang3.StringUtils
;
@AllArgsConstructor
@NoArgsConstructor
...
...
@@ -23,4 +24,12 @@ public class Contact {
private
String
department
;
private
SalesforceAttributes
attributes
;
public
String
getId
()
{
if
(
attributes
!=
null
&&
attributes
.
getUrl
()
!=
null
)
{
return
StringUtils
.
substringAfterLast
(
attributes
.
getUrl
(),
"/"
);
}
return
null
;
}
}
src/main/java/com/gitlab/johnjvester/salesforceintegrationservice/services/ContactService.java
View file @
7676e2eb
...
...
@@ -7,14 +7,20 @@ import com.gitlab.johnjvester.salesforceintegrationservice.models.PatchUpdates;
import
com.gitlab.johnjvester.salesforceintegrationservice.models.SalesforceLoginResult
;
import
com.gitlab.johnjvester.salesforceintegrationservice.models.SalesforceResponse
;
import
com.gitlab.johnjvester.salesforceintegrationservice.utils.BearerTokenUtilities
;
import
com.gitlab.johnjvester.salesforceintegrationservice.utils.HttpUtils
;
import
lombok.RequiredArgsConstructor
;
import
lombok.extern.slf4j.Slf4j
;
import
org.apache.commons.collections4.MapUtils
;
import
org.apache.commons.lang3.StringUtils
;
import
org.apache.http.HttpResponse
;
import
org.apache.http.client.methods.HttpGet
;
import
org.apache.http.client.methods.HttpPatch
;
import
org.apache.http.client.utils.URIBuilder
;
import
org.apache.http.entity.StringEntity
;
import
org.apache.http.impl.client.CloseableHttpClient
;
import
org.springframework.cache.annotation.CacheEvict
;
import
org.springframework.cache.annotation.Cacheable
;
import
org.springframework.http.MediaType
;
import
org.springframework.stereotype.Service
;
import
java.util.List
;
...
...
@@ -23,23 +29,48 @@ import java.util.List;
@RequiredArgsConstructor
@Service
public
class
ContactService
{
public
static
final
String
QUERY_PATH
=
"/services/data/v52.0/
query/
"
;
public
static
final
String
QUERY_PATH
=
"/services/data/v52.0/"
;
private
final
CloseableHttpClient
closeableHttpClient
;
private
final
ObjectMapper
objectMapper
;
private
final
SalesforceConfigurationProperties
salesforceConfigurationProperties
;
@Cacheable
(
"contacts"
)
public
Contact
getContact
(
String
id
)
throws
Exception
{
if
(
StringUtils
.
isEmpty
(
id
))
{
throw
new
NullPointerException
(
"id cannot be null"
);
}
SalesforceLoginResult
salesforceLoginResult
=
BearerTokenUtilities
.
loginToSalesforce
(
closeableHttpClient
,
salesforceConfigurationProperties
,
objectMapper
);
URIBuilder
builder
=
new
URIBuilder
(
salesforceLoginResult
.
getInstanceUrl
());
builder
.
setPath
(
QUERY_PATH
+
"sobjects/Contact/"
+
id
);
HttpGet
get
=
new
HttpGet
(
builder
.
build
());
get
.
setHeader
(
"Authorization"
,
"Bearer "
+
salesforceLoginResult
.
getAccessToken
());
HttpResponse
httpResponse
=
closeableHttpClient
.
execute
(
get
);
HttpUtils
.
checkResponse
(
httpResponse
);
Contact
contact
=
objectMapper
.
readValue
(
httpResponse
.
getEntity
().
getContent
(),
Contact
.
class
);
log
.
debug
(
"contact={}"
,
contact
);
return
contact
;
}
@Cacheable
(
"contacts"
)
public
List
<
Contact
>
getContacts
()
throws
Exception
{
SalesforceLoginResult
salesforceLoginResult
=
BearerTokenUtilities
.
loginToSalesforce
(
closeableHttpClient
,
salesforceConfigurationProperties
,
objectMapper
);
URIBuilder
builder
=
new
URIBuilder
(
salesforceLoginResult
.
getInstanceUrl
());
builder
.
setPath
(
QUERY_PATH
).
setParameter
(
"q"
,
Contact
.
CONTACT_QUERY
);
builder
.
setPath
(
QUERY_PATH
+
"query"
).
setParameter
(
"q"
,
Contact
.
CONTACT_QUERY
);
HttpGet
get
=
new
HttpGet
(
builder
.
build
());
get
.
setHeader
(
"Authorization"
,
"Bearer "
+
salesforceLoginResult
.
getAccessToken
());
HttpResponse
httpResponse
=
closeableHttpClient
.
execute
(
get
);
HttpUtils
.
checkResponse
(
httpResponse
);
SalesforceResponse
salesforceResponse
=
objectMapper
.
readValue
(
httpResponse
.
getEntity
().
getContent
(),
SalesforceResponse
.
class
);
List
<
Contact
>
contacts
=
salesforceResponse
.
getRecords
();
...
...
@@ -48,9 +79,32 @@ public class ContactService {
return
contacts
;
}
@CacheEvict
public
Contact
updateContact
(
PatchUpdates
patchUpdates
)
throws
Exception
{
@CacheEvict
(
value
=
"contacts"
,
allEntries
=
true
)
public
Contact
updateContact
(
String
id
,
PatchUpdates
patchUpdates
)
throws
Exception
{
log
.
debug
(
"updateContact(id={}, patchUpdates={})"
,
id
,
patchUpdates
);
if
(
StringUtils
.
isEmpty
(
id
))
{
throw
new
NullPointerException
(
"id cannot be null"
);
}
if
(
MapUtils
.
isEmpty
(
patchUpdates
))
{
throw
new
NullPointerException
(
"patchUpdates cannot be null"
);
}
SalesforceLoginResult
salesforceLoginResult
=
BearerTokenUtilities
.
loginToSalesforce
(
closeableHttpClient
,
salesforceConfigurationProperties
,
objectMapper
);
URIBuilder
builder
=
new
URIBuilder
(
salesforceLoginResult
.
getInstanceUrl
());
builder
.
setPath
(
QUERY_PATH
+
"sobjects/Contact/"
+
id
);
HttpPatch
patch
=
new
HttpPatch
(
builder
.
build
());
patch
.
setHeader
(
"Authorization"
,
"Bearer "
+
salesforceLoginResult
.
getAccessToken
());
patch
.
setHeader
(
"Content-type"
,
MediaType
.
APPLICATION_JSON_VALUE
);
patch
.
setEntity
(
new
StringEntity
(
objectMapper
.
writeValueAsString
(
patchUpdates
)));
HttpResponse
httpResponse
=
closeableHttpClient
.
execute
(
patch
);
HttpUtils
.
checkResponse
(
httpResponse
);
return
null
;
return
getContact
(
id
)
;
}
}
src/main/java/com/gitlab/johnjvester/salesforceintegrationservice/utils/HttpUtils.java
0 → 100644
View file @
7676e2eb
package
com.gitlab.johnjvester.salesforceintegrationservice.utils
;
import
org.apache.http.HttpResponse
;
public
final
class
HttpUtils
{
private
HttpUtils
()
{
}
public
static
void
checkResponse
(
HttpResponse
httpResponse
)
throws
Exception
{
// Simple validation to make sure the response is 2xx.
if
(
httpResponse
.
getStatusLine
().
getStatusCode
()
<
200
||
httpResponse
.
getStatusLine
().
getStatusCode
()
>
299
)
{
throw
new
Exception
(
httpResponse
.
getStatusLine
().
getReasonPhrase
());
}
}
}
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment