The rich text element allows you to create and format headings, paragraphs, blockquotes, images, and video all in one place instead of having to add and format them individually. Just double-click and easily create content.
A rich text element can be used with static or dynamic content. For static content, just drop it into any page and begin editing. For dynamic content, add a rich text field to any collection and then connect a rich text element to that field in the settings panel. Voila!
Headings, paragraphs, blockquotes, figures, images, and figure captions can all be styled after a class is added to the rich text element using the "When inside of" nested selector system.
With a growing focus on adopting microservices, developers often find it frustrating when someone modifies an API in a microservice. It is incredibly difficult to fully understand the impact of that change, which makes it difficult to throw blame around. It’s also hard to search through all microservices calling that API.
At Falcon, we have spent months developing a microservice architecture that improves production reliability, which ultimately benefits the end user. We have adopted an approach that notifies the developers of microservices that a change has been introduced, forcing developers to update their code before pushing it to their source code management tool.
With all the buzz about microservices, there is a real challenge when someone wants to:
This situation worsens when the number of microservices increases in a system landscape. If different microservices call this endpoint, then a developer has to change the structure in all of them. In order to do that, we need to:
Looking at Netflix, which has over 600 microservices, you’ll probably end up like this guy:
For testing a microservice, we have two options:
Both have their advantages but also a lot of disadvantages:
It’s not one silver bullet, but a combination of two things:
For the first point, many blogs and documents describe how to write test cases that call REST endpoints and then push the expected response. These libraries have existed for several years, and are well-established.
We’re focusing on Spring Cloud Contracts and how to write CDCs. If you don’t know what CDCs are, check out Consumer-Driven Contracts: A Service Evolution Pattern by Martin Fowler.
Falcon opts to use CDCs because they promote Acceptance Test-Driven Development (ATDD). This reduces conflicts that occur at later stages when we couple microservices. Through this approach, everyone is well versed in even the minute details of an API.
To explain the approach, let’s look at a simple example — a user calls a GET sentences API for n sentences. The consumer and producer are two microservices. The consumer builds a request with random words and sends a POST request to the producer. The producer then builds a sentence and returns it to consumer. The consumer gathers all sentences and returns an HTML page with all sentences.
Sequence diagram for demo application
We write simple groovy script that depicts the actual request and the associated response. Running mvn install goal on this project will result in the automatic generation of a test case, which will call the endpoint with the dummy request as stated in the contract. This will also bring an API response against the dummy response stated in the contract, and will generate stubs in a jar that you can use on the consumer side to mock API calls to this endpoint (we’ll get to that part later).
We need to add a spring-cloud-contract-verifier dependency in pom.xml, as well as a spring-cloud-contract plugin.
Earlier in pom.xml, we mentioned “BaseClass” while configuring the spring-cloud-contract plugin. The BaseClass is a simple SpringBootTest class that will be inherited by the generated test class and will provide the Spring context.
We also have an option to provide a base package for multiple base classes. This might be useful in a more complex project, but in this example, we have used one BaseClass for simplicity.
We’re going to write the contract in Groovy.
The contract should be placed in the package /src/test/resources/contracts/
It’s ok if you don’t know the syntax of groovy. If you’re using an IDE such as Intellij, you’ll get automatic suggestions.
Most of the contract is easy to comprehend. We are sending a POST request at /words URL with a JSON body containing: a subject, verb, article, adjective and noun. We expect a response with HTTP status 200 (ok), with the JSON body containing the UUID and sentence.
stubMatchers and testMatchers are optional parts to the above contract that help us in the following way:
stubMatchers (for the consumer side) define the dynamic values that should end up in a stub. A particular pattern of values in the request returns a response stated in the contract.
testMatchers (for the producer side) define regex for dynamic values in the response. In the above case, a random UUID is generated for each response, and we want our test case to pass for any UUID value; testMatchers provide this flexibility.
At this point we can run an mvn clean install which will automatically generate the test case. However, we’ll get a build failure, because we have not created a REST controller to perform the operation.
Also, we can share the generated stub with the developer working on the consumer side. This will enable the developer to start their work following a TDD approach. The generated stub will be installed in an .m2 folder. The generated stubs will be present in the output folder under /stubs/mapping/
Now let’s finish our work by writing a REST controller
and Autowire the same in our BaseClass. This is required to set up RestAssuredMockMvc in the BaseClass that we need for the generated test case.
Now, if we build our application by mvn clean install, we’ll get a successful build and we can rest assured that the API works as it is supposed to. The generated test case will be present at:
On the consumer side, we need to develop an API that calls the producer-side API. First, we need to write an integration test case for the consumer-side API. The stub generated on the producer side will be used to deploy a mock server that will respond to the request sent from the consumer API to the producer API.
Any change on the producer side will require a change in the contract. And any change in the contract will produce a stub that responds differently. By writing an integration test case, we are making sure that we get a build time failure. If any changes are made on the producer side without informing the developer who is working on the consumer side, we can immediately address the concern and stop the code release to QA or to the production environment.
We need to add pom dependencies to provision a mock server that will run the stubs.
Because we are following TDD, we need to write an integration test case that calls the consumer-side API. In this test class, we are going to configure the stub runner to mock API calls to the producer through simple annotations.
The test case is pretty basic. The important things to note are the annotations above the class declaration. Note the IDs property inside the @AutoConfigureStubRunner annotation. The format is:
These properties are the actual properties of producer side application.
com.akul.contract — is the group ID.
producer — is the artifact ID.
8020 — is the port on which the stub will run.
That’s it! We have successfully installed the stub, configured a mock server to run this stub and written a test case for our consumer-side API. In short, we have written a test to perform end-to-end testing of our feature API: /sentence that returns random sentences based on the query parameter number in the URL.
In order to finish our work, we need to write a controller that will perform an HTTP call to the producer API. In my example, I have used RestTemplate to call the producer-side API.
With this approach: