6. Spring Data MongoDB y API REST
As we know, the Spring Data project, included in the Spring platform, provides a framework to simplify data access and persistence over different information repositories. Within this project is Spring Data MongoDB, which provides integration with MongoDB databases, through a model centered on POJOs that interact with document collections and provides a data access repository.
In this section, and taking over from the previous unit, we are going to address the development of data access components through Spring Data, as well as microservices that offer this data through a REST API, all of this, following the MVC pattern that we already know.
6.1. Defining the Model – Document
A MongoDB database is made up of Document collections. Although these Documents may have different structures from each other or different types of data, the model does require a static structure. So, the first thing we must do is create a class that represents this Main Document for MongoDB, which will be the one returned by the queries that are made.
In this context, there are two main annotations that we will use:
@Document→ to indicate that a class corresponds to a domain object (domain object) that can be mapped in the database to offer persistence. This annotation for MongoDB would be the equivalent of@Entityin JPA. If nothing is indicated, the name of the collection to be used will be interpreted as corresponding to the name of the class in lower case. So, if we have the classcom.jaume.ad.Person, the collectionpersonwill be used. However, we can indicate the collection we are working with, either through the value or collection attributes, with the following syntax:@Document(value="collection")@Document("collection")@Document(collection="collection")@IdIt is applied to a field, and it is used to indicate that the field will be used as an identifier. As we know, every document in MongoDB requires an identifier. If one is not provided, the controller will assign anObjectIDautomatically. It is important to note that the types of data that we can use as identifiers can be bothStringsorBigInteger, since Spring will take care of converting them to the ObjectID type.
Important
It exists an anotation @DocumentReference to relate Documents one inside other, for instance when we store in a class objects from another classes, like relationships on SQL databases.
In addition to these, there are other more specific annotations that we can use. If you wish, you can consult them in the Spring Data MongoDB reference documentation here.
6.2. Defining the Repository
As we know, the repository is the interface in charge of managing access to data. In the case of MongoDB, this will derive from MongoRepository, which will be an interface parameterized by two arguments:
MongoRepository<T, Id>, who:T→ The type of document, which will correspond to the class defined in the model, andId→ The data type to which the identifier will belong.
The MongoRepository interface, as we have said, will be specific to MongoDB, and will derive from the CrudRepository and PagingAndSortingRepository interfaces, from which it will inherit all its methods. In this way, in the repository we will only have to declare those methods that are more specific for our application, since all the methods to implement CRUD operations, as well as findAll() and findById() will be inherited from MongoRepository.
To define our own queries in the repository, we will use the @Query annotation, providing the query in question as a value:
| Java | |
|---|---|
To supply parameters to the query, these are received as arguments to the method, and are referenced by their order in the query: ?0 for the first argument, ?1 for the second, etc. MAybe in newer version can be parameters in a nominal way, as :parameter_name
6.3. Defining the service
The services take care of the business layer of our application, and access the data through the repository, sending the results to the controller. These services, in general, are characterized by:
- Use the
@Serviceannotations, to indicate to Spring that a service is being implemented - On the one hand, the Service interface is usually defined and, on the other hand, the implementation is carried out through the
ServiceImplclass. - The
@Autowiredannotation is used in references to repositories to link or inject the service in question with said repository. - Once it gets the data from the repository, it sends it data to the controller.
6.4. Defining the controller
Finally, we are left with the controller implementation, which we already know from Spring. Let's remember the main characteristics of this one:
- Use the
@RestControllerannotation at the class level to indicate that you are dealing with a REST controller - Use the
@RequestMappingannotation at the class level to specify the base path for the service endpoints, - Use the
@Autowiredannotation in the properties that refer to the service, to inject it automatically, - Use the
@GetMapping,@PostMapping,@PutMapping,@DeleteMappingannotations on the methods that will implement GET, POST, PUT or DELETE type requests, specifying their Endpoint. - Use the
@PathVariableor@RequestParamor@RequestBodyannotation on the arguments of the above methods to get the values from path, request or body.
2. Swagger
Until now, we are testing our api rest with Postman, but now we offer a tool that integrates with Spring and Tomcat in order to test our API quickly and easily.
Swagger (https://swagger.io) is very simple to start:
- Add dependencies.
- Add a configuration class, who scans our controllers to find what entry points are defined.
- Create automoticaly a User Interface, who show what entries are defined and tools to test
2.1. Dependency
You must add at your pom.xml:
| XML | |
|---|---|
2.2. Configuration class
We need to create a class like this:
Two methods need to be implemented:
Docket apiDocket()→ who createa aDocket. ThisDocketcontains references to work and test our APIApiInfo getApiInfo()→ who create anApiInfo, and its name tells, is basic information about what is this API created for.
Attention
In las sample we have our controllers defindd in com.jaumeii.moviesapi.controller, and it is all that we could do.
2.3. Testing
When our spring project starts, we could see the log information:
| Text Only | |
|---|---|
It means that we have a new entry point /v2/api-docs. If we test this entry point, we get something like:
It is a json document who describes our API. But to work in a comfortable way, we can request /swagger-ui.html, and we get:
This UI page contains the basic information we set in getApiInfo() method. At the bottom we can see more element. If we open, we get:
We could see information about entry points and models that the API returns. Additionally, we could enter on each entry point to get information about parameters, and finally execute it.
3. Appendix. Solution to exercise about mongo queries
- Obtain all the productions that either premiered in
2015or are of theseriestype.
Tip
We need to use $or operator, with a condition array.
| JavaScript | |
|---|---|
- Get all the movies NOT released between the years
2000and2002.
Tip
We need to use $not operator, with a condition to deny.
| JavaScript | |
|---|---|
- Get all movies for which the "directors" key is not defined
Tip
We need to use $exists operator or checking for a null field.
- Get the title of all movies that start with the string
star wars, regardless uppercase.
Tip
It is interesting using regular expressions. Remembre to use i option to inlude a non case sensitive check.
| JavaScript | |
|---|---|
- Get the title of all movies that contain the comedy genre (
Comedy)
Tip
We look in the genres array for a given genre
| JavaScript | |
|---|---|
- Show the title and genres of the movies that contain either the comedy genre (
Comedy) or adventure (Adventure).
Tip
We need to prove that film math $all given genres.
- Get the title and genres of movies that have three genres.
Tip
We look for a genres array with three genres: $size operator.
| JavaScript | |
|---|---|
- Get the movies whose
Rotten Tomatoesrating is higher than4
Tip
We need to check into embedded documents, via dot notation inside a String :::
| JavaScript | |
|---|---|
- Make the same query as before, but limiting the number of documents to 10.
Tip
We need to limit results.
| JavaScript | |
|---|---|
- Now shows the title and rating of those movies with more than a 4 rating, ordered by rating (highest to lowest) and limiting the results to 10.
Tip
And now adding an ordering filter