lease see project documentation at https://ecosystem.atlassian.net/wiki/display/JRJC/. In order to start JIRA please execute atlas-debug from test directory. If you want contribute to project feel free to send pull request (preferably with tests ;)). IMPORTANT: please do not touch the rest_api_guard branch - master is being auto-merged to that branch so there is no need to do any changes there (doing so will cause conflicts). To run a single test class, you can pass -Dit.test=ExamplesTest to maven. In order to run integration tests on a snapshot cloud version of JIRA run: mvn clean integration-test -Djira.version=1001.0.0-SNAPSHOT -Pjira-cloud -nsu To run integrations tests manually, you need to set up JIRA with a running instance of postgres. To start a pre-setup postgres run docker run -p 5434:5432 docker.atlassian.io/jira-cloud/postgres-ci:9.5 and then in another terminal mvn jira:debug -Ddocker.host.address=-Ddatabase.port=5434 you can find your docker machine ip when running docker quickstart.
TechTalks
Wednesday, February 8, 2017
jira-rest-java-client
Sunday, April 3, 2016
What are the worst code smells you have ever encountered as a developer?
Code to exchange money between 2 banks.
So the system was - enter source bank, destination bank, source account, destination account, number of dollars.
As you can guess, the app was simple, and it was a web app written years ago.
The problem: One. Big. Source. File.
A giant JSP.
It was just a JSP which communicated with a mainframe.
And
the problem was that sometimes it transferred several times the same
amount of money... and also if the amount of money was too big, it
failed.
So the JSP had Java code to handle the "form.submit" as you would expect in... ASP or PHP app.
And since it had many pages, the dev decided to store the data in the session.
So the code was like:
If ( step == 1 )
{
grab_variables_from_sessi on();
process_data();
store_variables_in_sessio n();
step = 2;
}
else if (step == 2 )
{
.....
}
Needless
to say, the program was utter crap. But I was not allowed to modify it.
For some reason, banks prefer to stick to their technology which
clearly works as a dog with distemper.
So the
amount of money was too big to for a float. I changed it to double and
it started working correctly, but it took me almost a week just to find
the line to change... even if when they told me what the problem was, I
already had an idea that the float was the problem.
Thursday, January 15, 2015
Documenting a REST API with Swagger and Spring MVC
REST is now the most common way to expose web services. But how to say to clients how to use a REST API? There's no real standard or at least de facto standard to expose a REST contract. Many API resorts to a human-readable documentation, which is manually edited and thus hard to keep perfectly synchronized with the API. Another way is to create the documentation from the code itself, and this is what this article covers, by using Swagger on top of Spring MVC.
Swagger
Swagger is a specification for documenting REST API. It specifies the format (URL, method, and representation) to describe REST web services. It provides also tools to generate/compute the documentation from application code.
What does this mean? As an application developer, you write web services using your favorite framework, Swagger scans your code and exposes the documentation on some URL. Any client can consume this URL (which comes as XML or JSON documents) and learn how to use your REST web services: which HTTP methods to call on which URL, which input documents to send, which status code to expect, etc.
We're going to see how to use Swagger on top of Spring MVC, but remember Swagger is a specification and supports a wide range of frameworks.
The controller
The controller contains the basic CRUD operations, it uses the Spring MVC API:
@Controller @RequestMapping("/contacts") public class ContactController { @Autowired ContactService contactService; @ResponseBody @RequestMapping(method=RequestMethod.GET) public Collection<Contact> select() { return contactService.select(); } @ResponseBody @RequestMapping(value="/{id}",method=RequestMethod.GET) public Contact get(@PathVariable Long id) { return contactService.get(id); } @RequestMapping(method=RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public void add(@RequestBody Contact contact,HttpServletResponse response) { contactService.add(contact); String location = ServletUriComponentsBuilder.fromCurrentRequest() .pathSegment("{id}").buildAndExpand(contact.getId()) .toUriString(); response.setHeader("Location",location); } @RequestMapping(value="/{id}",method=RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public void update(@PathVariable Long id,@RequestBody Contact contact) { contact.setId(id); contactService.update(contact); } }
I made the controller as simple as possible, the point isn't to have a perfect, bullet-proof controller, but rather to illustrate the use of Swagger.
Swagger configuration
There's a nice and active project on github that provides Swagger support for Spring MVC. The XML configuration is straightforward:
class="com.mangofactory.swagger.configuration.DocumentationConfig" />
location="classpath:/swagger.properties" />
Swagger Spring MVC needs a couple of properties from a property file:
documentation.services.version=1.0 documentation.services.basePath=http://localhost:8080/zencontact
We'll see shortly how Swagger Spring MVC uses this 2 properties.
What's happening under the hood? Swagger Spring MVC scans the Spring MVC controllers on start-up and registers a documentation controller that exposes the operations the controllers allows. This documentation follows the Swagger specification: any client that understands this specification can use the API. The good news is the documentation is based on the code itself: any change to the code is reflected on the documentation, no need to maintain an external document.
Swagger Spring MVC uses Spring MVC annotations to compute the documentation, but it also understands Swagger annotations. Let's add the
@Api annotation on the controller:@Api(value = "contacts", description = "contacts") // Swagger annotation @Controller @RequestMapping("/contacts") public class ContactController { ... }
It's time now to discover the documentation.
The documentation
The documentation endpoint is on the
/api-docs URL, if we hit this URL and ask for JSON content, we'll get the following:{ "apiVersion": "1.0", "swaggerVersion": "1.0", "basePath": "http://localhost:8080/zencontact", "apis": [ { "path": "/api-docs/contacts", "description": "contacts" } ] }
Note we stumble on the 2 properties we set up previously, the version of our API and the base path of the API. They'll appear on each page of our documentation.
If we know we want to work on contacts, we just have to follow the link to find out more about the exposed operations on this resource. So let's hit
/api-docs/contacts, here is an excerpt of the result:{ "apiVersion": "1.0", "swaggerVersion": "1.0", "basePath": "http://localhost:8080/zencontact", "resourcePath": "/contacts", "apis": [ { "path": "/contacts", "description": "contacts", "operations": [ { "httpMethod": "GET", "summary": "select", "notes": "", "deprecated": false, "responseClass": "Collection[Contact]", "nickname": "select" } ] }, (...) other APIs and operations ], "models": { "Collection[Contact]": { "properties": { "empty": { "type": "boolean" } }, "type": "Collection[Contact]" }, "Contact": { "properties": { "id": { "type": "long" }, "lastname": { "type": "string" }, "firstname": { "type": "string" } }, "type": "Contact" } } }
There are 2 parts in this documentation: the operations and the models. A client can send a GET on the
/contacts URL to select the contacts. This is an example of an operation. We see this operation returns a collection of contacts. A client can learn more about this model in the models section. Note the Contact model, which is used by the PUT and POST operations (not shown above). All of this is scanned from the controller.
So far, so good: I write a controller and get its documentation for free. But this is only the beginning: let's see now how to consume this documentation, first from a programmatic client, and second from a neat user interface.
A client of the REST API
Let's see how a programmatic client manages to list the contacts by only knowing declaratively that it wants, that is the name of the resource, the description of the operation, and be sure it's a GET (read) operation. The unique entry point of the API is the documentation URL:
String documentationUrl = "http://localhost:8080/zencontact/api-docs" String resourceType = "contacts"; String documentation = tpl.getForObject(documentationUrl, String.class); // extracts http://localhost:8080/zencontact String basePath = JsonPath.read(documentation, "basePath"); // extracts /api-docs/contacts to discover the available operations on the contacts resource List<String> apiDocumentationPath = JsonPath.read( documentation, "apis[?].path", filter(where("description").is(resourceType)) );
Go back to the first JSON document if you're not sure about what the previous code snippet does. It actually extracts the path to the documentation of the contacts resource.
It's time now to discover the operation we want to use, so let's hit the resource documentation:
// let's go to http://localhost:8080/zencontact/api-docs/contacts documentation = tpl.getForObject(basePath+apiDocumentationPath.get(0), String.class); // selects the info about the "select" operation on "contacts" // we know it's GET, but we need to know the URL (it's actually "/contacts") List<String> apis = JsonPath.read( documentation, "$.apis[?].path", new OperationNicknameFilter("select","GET") ); // contains "/contacts" String resourcePath = apis.get(0); String contacts = tpl.getForObject(basePath+resourcePath, String.class);
This time, refer back to the second JSON document to understand what the client is doing. It basically searches the path of an operation whose nickname is
select and ensures this operation is exposed on a GET. Once it has the path, it sends the request and gets the following response, the contacts:[ { "id": 1, "firstname": "Erich", "lastname": "Gamma" }, { "id": 2, "firstname": "Richard", "lastname": "Helm" }, { "id": 3, "firstname": "Ralph", "lastname": "Johnson" }, { "id": 4, "firstname": "John", "lastname": "Vlissides" } ]
Isn't that great? With only the documentation URL as an entry point and a small idea about that it wants to do, the client can find the appropriate request to make. If we modify the controller, the client shouldn't break, as long as it follows the documentation. Nice decoupling.
What about HATEOAS?
The Swagger documentation implements HATEOAS: once a client reaches the documentation "homepage", it can follow the link to learn more about the API of the various resources the system exposes.
Do we need HATEOAS in our resources when we have the Swagger documentation? Of course we do. The Swagger documentation helps us to know about the resources and even about the expected formats. But the resources should expose links to navigate across each other.
The sample controller doesn't use HATEOAS for simplicity sake, but we can add links to the resources quite easily.
So see the Swagger documentation and HATEOAS in resources as complementary.
Let's see now another way to consume our documentation.
Swagger UI
Have you ever used a written-by-hand web service documentation which isn't up-to-date? I guess we're all familiar with that. The API developers are busy writing the API, they don't have time or forget to update the documentation, and the API client developers are trying to figure out how to use the API, but the documentation is broken or obsolete. Nobody is happy.
Imagine now the developers that write client applications can consult a beautiful UI that tells them how to use the API. The UI even tells them what kind of documents the API expects. This UI exists and is called Swagger UI:
Swagger UI just expects a URL that leads to a Swagger-compliant documentation. It then uses the documentation to display all the operations.
Swagger UI also inspects the models, so finding out about the structure of the JSON documents the API expects is straightforward. Here is an example for the PUT operation:
Note Swagger UI lets you try out operations and see the results.
Conclusion
Time to wrap up. I hope you're convinced tools like Swagger are the way to go to build real REST API and to get all the benefits this architecture style promises. Don't wait any longer and check how to include Swagger into your project, as it has out-of-the-box support for various REST frameworks (JAX-RS/Spring MVC for Java, Django for Python, etc).
Documenting a REST API with Swagger and Spring MVC
REST is now the most common way to expose web services. But how to say to clients how to use a REST API? There's no real standard or at least de facto standard to expose a REST contract. Many API resorts to a human-readable documentation, which is manually edited and thus hard to keep perfectly synchronized with the API. Another way is to create the documentation from the code itself, and this is what this article covers, by using Swagger on top of Spring MVC.
Swagger
Swagger is a specification for documenting REST API. It specifies the format (URL, method, and representation) to describe REST web services. It provides also tools to generate/compute the documentation from application code.
What does this mean? As an application developer, you write web services using your favorite framework, Swagger scans your code and exposes the documentation on some URL. Any client can consume this URL (which comes as XML or JSON documents) and learn how to use your REST web services: which HTTP methods to call on which URL, which input documents to send, which status code to expect, etc.
We're going to see how to use Swagger on top of Spring MVC, but remember Swagger is a specification and supports a wide range of frameworks.
The controller
The controller contains the basic CRUD operations, it uses the Spring MVC API:
@Controller @RequestMapping("/contacts") public class ContactController { @Autowired ContactService contactService; @ResponseBody @RequestMapping(method=RequestMethod.GET) public Collection<Contact> select() { return contactService.select(); } @ResponseBody @RequestMapping(value="/{id}",method=RequestMethod.GET) public Contact get(@PathVariable Long id) { return contactService.get(id); } @RequestMapping(method=RequestMethod.POST) @ResponseStatus(HttpStatus.CREATED) public void add(@RequestBody Contact contact,HttpServletResponse response) { contactService.add(contact); String location = ServletUriComponentsBuilder.fromCurrentRequest() .pathSegment("{id}").buildAndExpand(contact.getId()) .toUriString(); response.setHeader("Location",location); } @RequestMapping(value="/{id}",method=RequestMethod.PUT) @ResponseStatus(HttpStatus.NO_CONTENT) public void update(@PathVariable Long id,@RequestBody Contact contact) { contact.setId(id); contactService.update(contact); } }
I made the controller as simple as possible, the point isn't to have a perfect, bullet-proof controller, but rather to illustrate the use of Swagger.
Swagger configuration
There's a nice and active project on github that provides Swagger support for Spring MVC. The XML configuration is straightforward:
class="com.mangofactory.swagger.configuration.DocumentationConfig" />
location="classpath:/swagger.properties" />
Swagger Spring MVC needs a couple of properties from a property file:
documentation.services.version=1.0 documentation.services.basePath=http://localhost:8080/zencontact
We'll see shortly how Swagger Spring MVC uses this 2 properties.
What's happening under the hood? Swagger Spring MVC scans the Spring MVC controllers on start-up and registers a documentation controller that exposes the operations the controllers allows. This documentation follows the Swagger specification: any client that understands this specification can use the API. The good news is the documentation is based on the code itself: any change to the code is reflected on the documentation, no need to maintain an external document.
Swagger Spring MVC uses Spring MVC annotations to compute the documentation, but it also understands Swagger annotations. Let's add the
@Api annotation on the controller:@Api(value = "contacts", description = "contacts") // Swagger annotation @Controller @RequestMapping("/contacts") public class ContactController { ... }
It's time now to discover the documentation.
The documentation
The documentation endpoint is on the
/api-docs URL, if we hit this URL and ask for JSON content, we'll get the following:{ "apiVersion": "1.0", "swaggerVersion": "1.0", "basePath": "http://localhost:8080/zencontact", "apis": [ { "path": "/api-docs/contacts", "description": "contacts" } ] }
Note we stumble on the 2 properties we set up previously, the version of our API and the base path of the API. They'll appear on each page of our documentation.
If we know we want to work on contacts, we just have to follow the link to find out more about the exposed operations on this resource. So let's hit
/api-docs/contacts, here is an excerpt of the result:{ "apiVersion": "1.0", "swaggerVersion": "1.0", "basePath": "http://localhost:8080/zencontact", "resourcePath": "/contacts", "apis": [ { "path": "/contacts", "description": "contacts", "operations": [ { "httpMethod": "GET", "summary": "select", "notes": "", "deprecated": false, "responseClass": "Collection[Contact]", "nickname": "select" } ] }, (...) other APIs and operations ], "models": { "Collection[Contact]": { "properties": { "empty": { "type": "boolean" } }, "type": "Collection[Contact]" }, "Contact": { "properties": { "id": { "type": "long" }, "lastname": { "type": "string" }, "firstname": { "type": "string" } }, "type": "Contact" } } }
There are 2 parts in this documentation: the operations and the models. A client can send a GET on the
/contacts URL to select the contacts. This is an example of an operation. We see this operation returns a collection of contacts. A client can learn more about this model in the models section. Note the Contact model, which is used by the PUT and POST operations (not shown above). All of this is scanned from the controller.
So far, so good: I write a controller and get its documentation for free. But this is only the beginning: let's see now how to consume this documentation, first from a programmatic client, and second from a neat user interface.
A client of the REST API
Let's see how a programmatic client manages to list the contacts by only knowing declaratively that it wants, that is the name of the resource, the description of the operation, and be sure it's a GET (read) operation. The unique entry point of the API is the documentation URL:
String documentationUrl = "http://localhost:8080/zencontact/api-docs" String resourceType = "contacts"; String documentation = tpl.getForObject(documentationUrl, String.class); // extracts http://localhost:8080/zencontact String basePath = JsonPath.read(documentation, "basePath"); // extracts /api-docs/contacts to discover the available operations on the contacts resource List<String> apiDocumentationPath = JsonPath.read( documentation, "apis[?].path", filter(where("description").is(resourceType)) );
Go back to the first JSON document if you're not sure about what the previous code snippet does. It actually extracts the path to the documentation of the contacts resource.
It's time now to discover the operation we want to use, so let's hit the resource documentation:
// let's go to http://localhost:8080/zencontact/api-docs/contacts documentation = tpl.getForObject(basePath+apiDocumentationPath.get(0), String.class); // selects the info about the "select" operation on "contacts" // we know it's GET, but we need to know the URL (it's actually "/contacts") List<String> apis = JsonPath.read( documentation, "$.apis[?].path", new OperationNicknameFilter("select","GET") ); // contains "/contacts" String resourcePath = apis.get(0); String contacts = tpl.getForObject(basePath+resourcePath, String.class);
This time, refer back to the second JSON document to understand what the client is doing. It basically searches the path of an operation whose nickname is
select and ensures this operation is exposed on a GET. Once it has the path, it sends the request and gets the following response, the contacts:[ { "id": 1, "firstname": "Erich", "lastname": "Gamma" }, { "id": 2, "firstname": "Richard", "lastname": "Helm" }, { "id": 3, "firstname": "Ralph", "lastname": "Johnson" }, { "id": 4, "firstname": "John", "lastname": "Vlissides" } ]
Isn't that great? With only the documentation URL as an entry point and a small idea about that it wants to do, the client can find the appropriate request to make. If we modify the controller, the client shouldn't break, as long as it follows the documentation. Nice decoupling.
What about HATEOAS?
The Swagger documentation implements HATEOAS: once a client reaches the documentation "homepage", it can follow the link to learn more about the API of the various resources the system exposes.
Do we need HATEOAS in our resources when we have the Swagger documentation? Of course we do. The Swagger documentation helps us to know about the resources and even about the expected formats. But the resources should expose links to navigate across each other.
The sample controller doesn't use HATEOAS for simplicity sake, but we can add links to the resources quite easily.
So see the Swagger documentation and HATEOAS in resources as complementary.
Let's see now another way to consume our documentation.
Swagger UI
Have you ever used a written-by-hand web service documentation which isn't up-to-date? I guess we're all familiar with that. The API developers are busy writing the API, they don't have time or forget to update the documentation, and the API client developers are trying to figure out how to use the API, but the documentation is broken or obsolete. Nobody is happy.
Imagine now the developers that write client applications can consult a beautiful UI that tells them how to use the API. The UI even tells them what kind of documents the API expects. This UI exists and is called Swagger UI:
Swagger UI just expects a URL that leads to a Swagger-compliant documentation. It then uses the documentation to display all the operations.
Swagger UI also inspects the models, so finding out about the structure of the JSON documents the API expects is straightforward. Here is an example for the PUT operation:
Note Swagger UI lets you try out operations and see the results.
Conclusion
Time to wrap up. I hope you're convinced tools like Swagger are the way to go to build real REST API and to get all the benefits this architecture style promises. Don't wait any longer and check how to include Swagger into your project, as it has out-of-the-box support for various REST frameworks (JAX-RS/Spring MVC for Java, Django for Python, etc).
Subscribe to:
Comments (Atom)
Popup Generator
Popup generator software, popunder, dhtml popup, dhtml window. Bodog
Use bodog bonus code 1349384 to get a huge 110% bonus at bodog poker. Additionally the same code can be used at bodoglife property for an exclusive bonus. Chicago Limousine Service
Chicago limousine service offers professional limousine tours and airport transportation. Wedding Cars West Yorkshire
Bliss wedding cars is an independent family run business based in wakefield, offering chauffeur driven transport covering huddersfield, dewsbury, pontefract & the surrounding district. Rolls royce silver shadow, silver spur and jaguar sovereign. Casino Bonus Code
The highest exclusive online casino and online poker bonus codes. Also featuring daily updated poker and casino news as well as strategy articles.Add Url To Health And Medicine Directory
Health directory including health article, health rescources, man health, woman health, addiction, nutrition, herb, weight loss products Search Engine Optimization Dallas Internet Marketing Services
Multilingual search engine marketing consulting, and search friendly web design. Catanich internet marketing dallas texas is a team of internet marketing consultants providing website marketing consulting services to online internet companiesAmpliación Del Pene
Por los 6 años pasados vigrx ha contenido como el suplemento masculino del virility del número 1 se convirtió científico para dar resultados seguros y eficaces ustedAdd Your Website To 100 Web Directories.
Add your website to 100 web directories. Herbal Viagra
Herbal supplements at an affordable price! Home Speakers
Search through this great collection of brand name speakers Truck Graphics
Customize rear window graphics for your vehicle, truck, suv or car! Truck window decals and more are available. Our categories are: art, fantasy, fishing, horses, hunting, military, nature, patriotic, racing, snow sports, and wildlife. Singapore Seminars
Singaporeseminars. Com is singapore's no. 1 seminar, events & conference portal. Looking for the best resources, here's the one stop portal in singapore. Chicago Limousine Service
Chicago limousine service offers professional limousine tours and airport transportation. Classic Cars Market Place Advertising Broker Services
Classic cars market place advertising brokers services will sell or find the car of your dreams. Antique custom vehicle,vintage car,hot rod,hemi engines. The american hot muscle car dream just a click away. We are your no1 marketing classiccar center Domalot Web Hosting
Offers cheap shared, virtual dedicated and dedicated web hosting services: linux or windows hosts. Also provides search, registration and transfers for domain names.
Popup generator software, popunder, dhtml popup, dhtml window. Bodog
Use bodog bonus code 1349384 to get a huge 110% bonus at bodog poker. Additionally the same code can be used at bodoglife property for an exclusive bonus. Chicago Limousine Service
Chicago limousine service offers professional limousine tours and airport transportation. Wedding Cars West Yorkshire
Bliss wedding cars is an independent family run business based in wakefield, offering chauffeur driven transport covering huddersfield, dewsbury, pontefract & the surrounding district. Rolls royce silver shadow, silver spur and jaguar sovereign. Casino Bonus Code
The highest exclusive online casino and online poker bonus codes. Also featuring daily updated poker and casino news as well as strategy articles.Add Url To Health And Medicine Directory
Health directory including health article, health rescources, man health, woman health, addiction, nutrition, herb, weight loss products Search Engine Optimization Dallas Internet Marketing Services
Multilingual search engine marketing consulting, and search friendly web design. Catanich internet marketing dallas texas is a team of internet marketing consultants providing website marketing consulting services to online internet companiesAmpliación Del Pene
Por los 6 años pasados vigrx ha contenido como el suplemento masculino del virility del número 1 se convirtió científico para dar resultados seguros y eficaces ustedAdd Your Website To 100 Web Directories.
Add your website to 100 web directories. Herbal Viagra
Herbal supplements at an affordable price! Home Speakers
Search through this great collection of brand name speakers Truck Graphics
Customize rear window graphics for your vehicle, truck, suv or car! Truck window decals and more are available. Our categories are: art, fantasy, fishing, horses, hunting, military, nature, patriotic, racing, snow sports, and wildlife. Singapore Seminars
Singaporeseminars. Com is singapore's no. 1 seminar, events & conference portal. Looking for the best resources, here's the one stop portal in singapore. Chicago Limousine Service
Chicago limousine service offers professional limousine tours and airport transportation. Classic Cars Market Place Advertising Broker Services
Classic cars market place advertising brokers services will sell or find the car of your dreams. Antique custom vehicle,vintage car,hot rod,hemi engines. The american hot muscle car dream just a click away. We are your no1 marketing classiccar center Domalot Web Hosting
Offers cheap shared, virtual dedicated and dedicated web hosting services: linux or windows hosts. Also provides search, registration and transfers for domain names.