One of the most usual tasks requested for back-end developers is generating a microservices oriented API. When we talk about microservices, we refer to small sets of endpoints, each one of them resolving a different problem, which can be deployed individually in a fast and simple way, so they are easy to escalate in case we need to take care of high amount of requests in a certain area. This is a great advantage compared to the classic monolithic architecture, which requires the deployment of all the services at once, taking more time and resources.
REST services are more efficient than SOAP services, and also easier to securize, so it’s no surprise they are becoming so popular, but deploying and testing the services can be troublesome. Fortunately there are some frameworks which provide us some easy-to-use tools.
Let’s split this issue in 3 steps:
Generating the REST service using JSON.
Booting the service with Spring boot.
Document it and get a user-friendly interface for tests with Swagger.
In our example code, we are going to simulate a small system to handle a videogame database via REST. The code packages will be defined as follows:
The API package will contain all the REST API, dividing it by layers (services, data access and data transfer objects), and providing the controller with the endpoints.
To set up the swagger system we will need a configuration file, plus the API package classes should get new annotations to document its content.
Finally we will add the generic Spring boot runner, which may be used for any package and requires very little tuning.
Process
1. Designing a dummy RESTful web service
The first step is creating a basic structure for the REST service. We’ll split it up in different layers:
The controller would be VideogameController, and would contain all the endpoints, we’ll leave this for later as, we’ll talk about setting it up with swagger.
The interface IVideogameService will define the service layer, which would have the “normal” endpoints.
The IVideogameDAO gives an idea of the methods available through the Data Access Layer. In order to void much otrouble setting up a database connection or a real repository, we will mock it.
A good practice is to split the design and the implementation by using interfaces. It’s not really necessary, but it will make the code more reusable.
graph TD
A[VideogameController]
B[IVideogameService]
C[IVideogameDao]
A --> B;
B --> C;
Therefore the Service would simulate commonly known as CRUD operations: get (find), set (update), add (save) and remove (delete).
But in this case we want to keep it simple since we are focusing on the services layer., so instead of configuring a database connection and writting some queries, we are going to mock it with a simple Map structure.
The Data Transfer Object or DTO isn’t really interesting right now, as it would be just as simple as a class with a couple of Strings to define its attributes. So we will skip its content for now.
Finally, we will refer to the endpoint as the Controller, and since we would be using a REST service with JSON, we will need to add its maven dependency.
The Controller for Spring MVC would be an extra layer where most of the interesting things we are studying today will happen. First of all, we are going to connect it with the service, and set up the REST via spring JAX-RS annotations:
RequestMapping configures the path.
RequestMapping states the method expects an HTTP request.
RequestBody gets the information from the HTTP body.
PathVariable gets a value from the URL.
ResponseStatus will store the status code to send back.
ResponseBody gets the information from the HTTP body
With this we are all set-up, so let’s find somewhere to run this code.
2. Let’s boot it!
Spring boot is a tool to generate a “just run” application, which can be set up with only a few lines of code an annotations, without any xml configuration. This makes it really interesting in order to run and test Java microservices really fast.
Let’s start by adding its maven dependencies and setting up its just run configuration:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
<dependencies> <!-- spring boot setup ability --> <dependency> <groupId>org.springframework.boot>/groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <!-- Just run configuration --> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
Then, we need to set it up in the Java code itself. The longest way to configure it would be using the following annotations:
RestController, it’s an Spring-MVC, which sets up this class as controller for a REST service
EnableAutoConfiguration, this configures the boot service according to dependencies we have included. Since we used TesController, the system will consider to add Spring MVC and Tomcat.
ComponentScan, scans the components of the package and its children packages.
But all this 3 annotations can be reduced to a single one: SpringBootApplication (scanBasePackages = { “replace_with_main_package” }), which is the one used in the example.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; /** * Generic SpringBoot, only configured by setting the scanBasePackages * restricts the scanned packages */ @SpringBootApplication(scanBasePackages = { "org.thalion.snippet.swagger" }) publicclassSpringbootRunner { publicstaticvoidmain(String[] args) { SpringApplication.run(SpringbootRunner.class, args); } }
So just by running this class, a local server will be deployed, and we are ready to test the service… but that’s not intuitive. Let’s make it better.
3. Making it pretty and easy to test, plus avoiding setting up the client side
Documenting an API to make it easy to understand for other developers, and make it friendly for the testers is no easy task. Swagger is a framework which, using a few extra annotations, is able to generate a simple web user interface with REST calls to the API documented, using the metadata available. We are going to use the springfox version, as it comes already bundled with the correct annotations.
❕This was the stable version when the post was originally written.
Api: for controller classes, it sets the API endpoint documentation.
Apimodel: for Data Transfer Objects class names.
ApiModelProperty: for Data Transfer Objects attributes.
ApiOperation: they go above the methods or services available on an endpoint.
ApiParam: for input parameter on a method.
ApiResponse: for output parameters. You can have more than one with a set of ApiResponses (e.g. also add the 404 error, etc).
Then, in order to fully set this up, there are 2 important points to recheck: the DTO and the controller.
Let’s start with the DTO, as it’s the most straight-forward part: we only need to document the information about the class definition itself and the attributes.
import java.util.Collection; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; 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.RequestMethod; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; import org.thalion.snippet.swagger.api.dto.Videogame; import org.thalion.snippet.swagger.api.service.IVideogameService; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; import io.swagger.annotations.ApiResponse; import io.swagger.annotations.ApiResponses; @RestController @RequestMapping("/api/videogames") publicclassVideogameController { @Autowired private IVideogameService service; @ResponseStatus(HttpStatus.OK) @RequestMapping(method = RequestMethod.GET, produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Get Videogames", notes = "Returns all the videogame data") @ApiResponses({ @ApiResponse(code = 200, message = "Returns this information") }) public Collection<Videogame> getAllVideogames() { return service.findAll(); } @ResponseStatus(HttpStatus.OK) @RequestMapping(method = RequestMethod.GET, value = "{name}", produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Get the info for one videogame", notes = "Returns the info from one videogame") @ApiResponses({ @ApiResponse(code = 200, message = "Exists this information") }) public Videogame getVideogameByName( @ApiParam(defaultValue = "default", value = "The name of the videogame to return") @PathVariable String name) { return service.findOne(name); } @RequestMapping(method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = "Create videogame information", notes = "Create a videogame entry") @ApiResponses({ @ApiResponse(code = 201, message = "The videgame entry was created successfully") }) public ResponseEntity<String> createVideogame(@RequestBody Videogame videogame) { StringvideogameCreatedId= service.save(videogame); returnnewResponseEntity<String>(videogameCreatedId, HttpStatus.CREATED); } @ResponseStatus(HttpStatus.NO_CONTENT) @RequestMapping(method = RequestMethod.PUT, value = "{name}") @ApiOperation(value = "Update videogame information", notes = "Update a videogame information entry") @ApiResponses({ @ApiResponse(code = 204, message = "The videgame entry was updated successfully") }) publicvoidupdateVideogame( @ApiParam(defaultValue = "Default", value = "The name of the videogame to update") @PathVariable String name, @RequestBody Videogame videogame) { videogame.setName(name); service.update(videogame); } @ResponseStatus(HttpStatus.NO_CONTENT) @RequestMapping(method = RequestMethod.DELETE, value = "{name}") @ApiOperation(value = "Delete videogame", notes = "Deletes a videogame entry") @ApiResponses({ @ApiResponse(code = 204, message = "The videgame entry was deleted successfully") }) publicvoiddeleteInfo( @ApiParam(defaultValue = "Default", value = "The name of the videogame to delete") @PathVariable String name) { service.delete(name); } }
Once all the documentation annotations have been written down, we just need to configure the API page with the help of a Docket builder, which provides the primary graphic interface for our swagger implementation.
Since we are working with an API, we are only going to worry about the URLs under the /api/ pattern, which we can select with the help of regular expressions.
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; @Configuration @EnableSwagger2 publicclassSwaggerConfig { @Bean public Docket newsApi() { returnnewDocket(DocumentationType.SWAGGER_2).groupName("api-videogames") .apiInfo(apiVideogames()).select().paths(PathSelectors.regex("/api.*")).build(); } private ApiInfo apiVideogames() { returnnewApiInfoBuilder().title("Videogames REST api POC") .description("PoC of a REST api, to test both Springboot and Swagger") .termsOfServiceUrl("https://creativecommons.org/licenses/by/4.0/") .contact("abcd@mail.com") .license("GNU General Public License v3.0").licenseUrl( "https://www.gnu.org/licenses/gpl-3.0.en.html").version("3.0").build(); } }
And we finally get this beautiful webpage with all the endpoints, which we can easily interact with on localhost:8080/swagger-ui.html. We can interact with the different methods and set up the arguments to do quick tests, avoiding the need to write a client or using a REST requests generator like SoapUI.
Congratulations! your demo is completely set up and ready to go.
I was recently requested to debug a pre-.NET application Visual Basic, so I had to set up the environment for Windows 98 development… but nowdays all that software is deprecated and has no support. This is what I learned from my experience to get it up and running, but in case you can make a choice, I’d recommend you to rewrite the code in .NET, as this kind of DLL code relies platform, and things have changed a lot in 20 years.
Process
1.- Delete all the files from the previously failed VB6 installation attempts
Be careful to avoid deleting the recent Visual Studio versions, as they may have similar paths.
The Visual Studio 6.0 files are by default under ‘C:\Program Files (x86)’ in 64 bits systems.
2.- Modify the installation files to adapt them to current tech
First of all you will need a copy of the Visual Studio installer in your hard drive. Icopied the content of an old college licensed CD into a folder, and proceeded to edit.
Open ‘SETUPWIZ.INI’ with a text editor (e.g. Notepad++), and replace ‘VmPath=ie4\msjavx86.exe’, which tries to install a really old Java implementation and makes the installation process fail, with an empty va. So the first part of the file should look like this:
You must also edit the ‘SETUP.EXE’ properties. Go to the context menu of the file (right click as default), select properties, and got to the ‘compatibility’ tab. Check that you have selected:
Compatibility mode: execute as ‘Windows XP (Service Pack 3)’.
Configuration: ‘execute this program as administrator’.
3.- Execute the wizard installer
Open the context menu of ‘SETUP.EXE’ and choose ‘run as administrator’.
Don’t install ‘Source Safe’, as it fails.
When we get to ‘choose the installation mode’ select ‘Custom’. Then follow these steps:
Do not install (as they fail):
Microsoft Visual FoxPro 6.0
Microsoft Visual InterDev 6.0
Microsoft Visual SourceDafe 6.0
ActiveX (obsolete version, generates conflict with the current version)
Install the unicode libraries: from the custom main menu, select the text ‘Microsoft Visual C++ 6.0’, and the button ‘Change option’ on the right side will be set as active. Click on it and follow a similar process for ‘VC++ MFC and Template Libraries’ and ‘MS Foundation Class Libraries’. Finally select all these options:
Static libraries
Shared libraries
Static libraries for Unicode
Shared libraries for Unicode
Browser database
Source code
Install the database: from the main ‘Custom’ menu, click on the ‘Data Access’ text , and the button ‘Change option’ on the right side will be set as active. Click on it and make sure that ‘ADO, RDS and OLE DB Providers’ is not selected. You will get a warning message saying that this component is esential for the application, but you should ignore it, as it will crash on Windows 10. Do select only the following options:
Microsoft ODBC Drivers
Remote Data Objects and Controls
Data environment
Install the tools: from the main ‘Custom’ menu, click on the ‘Enterprise Tools’ text, and the button ‘Change option’ on the right side will be set as active. Check that ‘Visual Studio Analyzer’ is not selected. Therefore, select only:
Aplication Performance Explorer
Repository
Visual Component Manager
Visual Basic Enterprise Components
VC++ Enterprise Tools
Microsoft Visual Modeler
As the last step, before pressing on ‘Finish’, do not let the program configure the environment vars.
If you have waited more than 5 minutes and the program is still ‘configuring the system’, you can assume something has gone wrong and the install has been frozen somewhere. Cancel it, clean up (see the first section on top of this post) and start all over again, reading carefully the steps.
If there is an error message about the Java machine you can ignore it. At that point you should be able by then to run ‘Visual Basic’ without the MSDN help package, so you get the bare bones yet fully functional experience.
4.- Execute the application
Run it always in administrator mode (right click on Visual Basic 6.0, and select ‘run as administrator’). Then, here it is, ready to run and debug ancient DLLs.
❗️ If you want it the program to run using a Microsoft Office 2010 instance, you will need to load some dependencies. Go to ‘Project/References’ and select:
# --save-dev will only add the dependencies to dev, not production npm install --save-dev gulp npm install --save-dev gulp-concat # concat files npm install --save-dev gulp-uglify # minify
// A task 'statics' will run other 2 asynchronous tasks gulp.task('statics', ['myTask1', 'myTask2']);
Task dependecies
1 2 3 4 5 6
gulp.task('myTask2', ['myTask'], function () { /* * 'myTask2' function * it will only be executed after 'myTask' has finsihed */ });
Default task
1 2 3 4 5 6 7 8
// it will run just by tyoing `gulp` in the terminal gulp.task('default', function () { /* * Default rask code */ }); // you can also make your default a list of tasks gulp.task('default', ['myTask1', 'myTask2']);
gulp.src()
1 2 3 4 5 6
gulp.src('js/source/1.js') #get only 'js/source/1.js' gulp.src('js/source/*.js') # all the '.js' files in `js/source/` gulp.src('js/**/*.js') #get only '.js' files from `js/` and its subfolder gulp.src('!js/source/2.js') # exclude `2.js'` gulp.src(`static/*.+(js|css)`) # all the files which finish in `js` or `css` # this can be piped or be sent to `gulp.dest()`
pipe()
1 2 3
//read, edit stream data .pipe(concat('todo.js')) .pipe(uglify())
gulp.dest()
1 2
// write the stream in the folder .pipe(gulp.dest('js/build/'))
gulp.watch()
1 2 3 4 5 6
// check the file and execute the task when it is edited gulp.watch('js/source/*.js', ['myTask']); // you can use it with a callback too gulp.watch('js/source/*.js', function(){ // callback function });
There can be a NoCommand (empty slot in a controller)
There can be an undo method (e.g. turn off lightbulb on controller)
Decorator
Structural, add behaviour to a particular object, as opposed to class objets (the others are unmodified) (e.g. java.io.Reader/*component*/: InputStreamReader/*concreteComponent*/ and BufferedReader /*decorator*/)
3 elements
Component(hang())
ConcreteComponent(hang()) //inheritance from Component
Decorator(hang()) //inheritance from Component, uses component