Step 1 - Simple Consumer calling Provider
Move to step 1
git checkout step1
- Javascript
npm install
Learning Objectives
Step | Title | Concept Covered | Learning objectives | Further Reading |
---|---|---|---|---|
step 1 | Create our consumer before the Provider API even exists | Consumer-driven design |
|
We need to first create an HTTP client to make the calls to our provider service:
The Consumer has implemented the product service client which has the following:
GET /products
- Retrieve all productsGET /products/{id}
- Retrieve a single product by ID
The diagram below highlights the interaction for retrieving a product with ID 10:
You can see the client interface we created
- Javascript
in consumer/src/api.js
:
export class API {
constructor(url) {
if (url === undefined || url === "") {
url = process.env.REACT_APP_API_BASE_URL;
}
if (url.endsWith("/")) {
url = url.substr(0, url.length - 1)
}
this.url = url
}
withPath(path) {
if (!path.startsWith("/")) {
path = "/" + path
}
return `${this.url}${path}`
}
async getAllProducts() {
return axios.get(this.withPath("/products"))
.then(r => r.data);
}
async getProduct(id) {
return axios.get(this.withPath("/products/" + id))
.then(r => r.data);
}
}
in consumer/src/main/java/io/pact/workshop/product_catalogue/clients/ProductServiceClient.java
:
@Service
public class ProductServiceClient {
@Autowired
private RestTemplate restTemplate;
@Value("${serviceClients.products.baseUrl}")
private String baseUrl;
public ProductServiceResponse fetchProducts() {
return restTemplate.getForObject(baseUrl + "/products", ProductServiceResponse.class);
}
public Product fetchProductById(long id) {
return restTemplate.getForObject(baseUrl + "/products/" + id, Product.class);
}
}
in consumer/src/main/au/com/dius/pactworkshop/consumer/ProductService.java
:
@Service
public class ProductService {
private final RestTemplate restTemplate;
@Autowired
public ProductService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public List<Product> getAllProducts() {
return restTemplate.exchange("/products",
HttpMethod.GET,
null,
new ParameterizedTypeReference<List<Product>>(){}).getBody();
}
public Product getProduct(String id) {
return restTemplate.getForEntity("/products/{id}", Product.class, id).getBody();
}
}
in client.rb
:
require 'httparty'
require 'uri'
require 'json'
class Client
def load_provider_json
response = HTTParty.get(URI::encode('http://localhost:8081/provider.json?valid_date=' + Time.now.httpdate))
if response.success?
JSON.parse(response.body)
end
end
end
in Consumer/src/ApiClient.cs
:
using System;
using System.Net.Http;
using System.Threading.Tasks;
namespace Consumer
{
public class ApiClient
{
private readonly Uri BaseUri;
public ApiClient(Uri baseUri)
{
this.BaseUri = baseUri;
}
public async Task<HttpResponseMessage> GetAllProducts()
{
using (var client = new HttpClient { BaseAddress = BaseUri })
{
try
{
var response = await client.GetAsync($"/api/products");
return response;
}
catch (Exception ex)
{
throw new Exception("There was a problem connecting to Products API.", ex);
}
}
}
public async Task<HttpResponseMessage> GetProduct(int id)
{
using (var client = new HttpClient { BaseAddress = BaseUri })
{
try
{
var response = await client.GetAsync($"/api/product/{id}");
return response;
}
catch (Exception ex)
{
throw new Exception("There was a problem connecting to Products API.", ex);
}
}
}
}
}
in the consumer/client
package:
type Client struct {
BaseURL *url.URL
httpClient *http.Client
}
// GetUser gets a single user from the API
func (c *Client) GetUser(id int) (*model.User, error) {
}
After forking or cloning the repository, we may want to install the dependencies npm install
.
We can run the client with npm start --prefix consumer
- it should fail with the error below, because the Provider is not running.
Move on to step 2