Polish reference guide

See gh-295
This commit is contained in:
Stephane Nicoll 2017-02-02 13:31:00 +01:00
parent 6242df5b6e
commit b356e233a2
13 changed files with 432 additions and 216 deletions

View File

@ -9,6 +9,10 @@
<artifactId>initializr-docs</artifactId>
<name>Spring Initializr :: Docs</name>
<properties>
<snippets.location>${project.build.directory}/snippets</snippets.location>
</properties>
<dependencies>
<dependency>
<groupId>io.spring.initializr</groupId>
@ -56,10 +60,34 @@
<id>docs</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-restdocs-snippets</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr-web</artifactId>
<version>${project.version}</version>
<classifier>snippets</classifier>
<type>zip</type>
<outputDirectory>${snippets.location}</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.0</version>
<executions>
<execution>
<id>generate-docbook</id>
@ -73,8 +101,10 @@
<doctype>book</doctype>
<attributes>
<docinfo>true</docinfo>
<spring-boot-version>${spring.boot.version}</spring-boot-version>
<snippets>${basedir}/../initializr-web/target/snippets</snippets>
<spring-initializr-version>${project.version}</spring-initializr-version>
<spring-initializr-docs-version>${project.version}</spring-initializr-docs-version>
<snippets>${snippets.location}</snippets>
<github-tag>${github-tag}</github-tag>
</attributes>
</configuration>
</execution>
@ -83,7 +113,6 @@
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.15</version>
<configuration>
<sourceDirectory>${basedir}/target/generated-docs</sourceDirectory>
<includes>index.xml</includes>
@ -244,6 +273,22 @@
</target>
</configuration>
</execution>
<execution>
<id>setup-maven-properties</id>
<phase>validate</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<exportAntProperties>true</exportAntProperties>
<target>
<taskdef resource="net/sf/antcontrib/antcontrib.properties" />
<taskdef name="stringutil" classname="ise.antelope.tasks.StringUtilTask" />
<var name="github-tag" value="v${project.version}" />
<propertyregex property="github-tag" override="true" input="${github-tag}" regexp=".*SNAPSHOT" replace="master" />
</target>
</configuration>
</execution>
</executions>
</plugin>
<plugin>

View File

@ -1,36 +1,59 @@
:code: https://github.com/spring-io/initializr/tree/master/initializr
:service: https://github.com/spring-io/initializr/tree/master/initializr-service
[[configuration-format]]
# Configuration Format
This section describes the configuration structure that is used by the initializr.
The metadata provided through configuration are driving the options exposed by a
particular instance and <<metadata-format.adoc#metadata-format,the project metadata
format>>.
# Configuration Guide
This section describes the configuration structure that is used by the initializr. The metadata provided through configuration are actually used to generate the link:Project-metadata-json-output[Project metadata json format].
TIP: A good way to get started with the configuration is to look at the {service}/src/main/resources/application.yml[configuration of the production instance] and check the end-result on https://start.spring.io
TIP: A good way to get started with the configuration is to look at the
{sc-initializr-service}/resources/application.yml[configuration of the production
instance] and check the end-result on https://start.spring.io
The configuration is split in several sections:
* An `env` section used to provide various global settings
* A `dependencies` section lists the available dependencies. This is the most important section of the service as it defines the "libraries" that the user can choose
* The `groupId`, `artifactId`, `version`, `name`, `description` and `packageName` provide default values for these project settings
* The `types`, `packagings`, `javaVersions`, `languages` and `bootVersions` provide the list of available option for each setting and which one is the default.
* An `env` section used to provide various global settings.
* A `dependencies` section lists the available dependencies. This is the most
important section of the service as it defines the "libraries" that the user can
choose.
* The `groupId`, `artifactId`, `version`, `name`, `description` and `packageName`
provide default values for these project settings.
* The `types`, `packagings`, `javaVersions`, `languages` and `bootVersions` provide
the list of available option for each setting and which one is the default.
## Env section
TIP: Check {code}/src/main/groovy/io/spring/initializr/metadata/InitializrConfiguration.groovy#L113[the code] for a full list of the available configuration options.
TIP: Check {sc-initializr-generator}/metadata/InitializrConfiguration.groovy#L113[the code]
for a full list of the available configuration options.
The `env` element defines environment option that the service uses:
* `artifactRepository`: the URL of the (maven) repository that should be used to download the Spring Boot CLI distribution bundle. This is only used by the `/spring` endpoint at the moment
* `springBootMetadataUrl` the URL of the resource that provides the list of available Spring Boot versions.
* `forceSsl`: a boolean flag that determines if we should use `https` even when browsing a resource via `http`. This is _enabled_ by default.
* `fallbackApplicationName`: the name of the _default_ application. Application names are generated based on the project's name. However, some user input may result in an invalid identifier for a Java class name for instance.
* `invalidApplicationNames`: a fixed list of invalid application names. If a project generation uses one of these names, the fallback is used instead
* `invalidPackageNames`: a fixed list of invalid package names. If a project generation uses one of these names, the default is used instead
* `googleAnalyticsTrackingCode`: the Google Analytics code to use. If this is set, Google analytics is automatically enabled
* `kotlin`: kotlin-specific settings. For now, only the kotlin version to use can be configured
* `maven`: maven-specified settings. A custom maven parent POM can be defined and whether or not the `spring-boot-dependencies` BOM should be automatically added to the project
* `artifactRepository`: the URL of the (maven) repository that should be used to
download the Spring Boot CLI distribution bundle. This is only used by the `/spring`
endpoint at the moment.
* `springBootMetadataUrl` the URL of the resource that provides the list of available
Spring Boot versions..
* `forceSsl`: a boolean flag that determines if we should use `https` even when
browsing a resource via `http`. This is _enabled_ by default.
* `fallbackApplicationName`: the name of the _default_ application. Application names
are generated based on the project's name. However, some user input may result in an
invalid identifier for a Java class name for instance.
* `invalidApplicationNames`: a fixed list of invalid application names. If a project
generation uses one of these names, the fallback is used instead.
* `invalidPackageNames`: a fixed list of invalid package names. If a project
generation uses one of these names, the default is used instead.
* `googleAnalyticsTrackingCode`: the Google Analytics code to use. If this is set,
Google analytics is automatically enabled.
* `kotlin`: kotlin-specific settings. For now, only the kotlin version to use can be
configured.
* `maven`: maven-specified settings. A custom maven parent POM can be defined and
whether or not the `spring-boot-dependencies` BOM should be automatically added to
the project.
If some of your dependencies require a custom Bill of Materials (BOM) and/or a custom repository, you can add them here and use the id as a reference. For instance, let's say that you want to integrate with library `foo` and it requires a `foo-bom` and a `foo-repo`. You can configure things as follows:
If some of your dependencies require a custom Bill of Materials (BOM) and/or a custom
repository, you can add them here and use the id as a reference. For instance, let's
say that you want to integrate with library `foo` and it requires a `foo-bom` and a
`foo-repo`. You can configure things as follows:
```yml
initializr:
@ -47,25 +70,37 @@ initializr:
snapshotsEnabled: false
```
You can then use the `foo-bom` and `foo-repo` in a "dependency" or "dependency group" section.
You can then use the `foo-bom` and `foo-repo` in a "dependency" or "dependency group"
section.
NOTE: The `spring-milestones` and `spring-snapshots` repositories are available by default. Please note that these are just references and won't impact the project unless you choose a dependency that explicitly refer to a bom and/or repo by id. Check the example below for more details.
NOTE: The `spring-milestones` and `spring-snapshots` repositories are available by
default. Please note that these are just references and won't impact the project
unless you choose a dependency that explicitly refer to a bom and/or repo by id.
Check the example below for more details.
## Dependencies section
The `dependencies` section allows you define a list of groups, each group having one more `dependency`. A group gather dependencies that share a common characteristics (i.e. all web-related dependencies for instance).
The `dependencies` section allows you define a list of groups, each group having one
more `dependency`. A group gather dependencies that share a common characteristics
(i.e. all web-related dependencies for instance).
A `dependency` has the following basic characteristics:
* A mandatory identifier. If no further information is provided, a Spring Boot starer with that id is assumed
* A `name` and `description` used in the generated meta-data and the web ui
* A `groupId` and `artifactId` to define the coordinates of the dependency
* A `version` if Spring Boot does not already provide a dependency management for that dependency
* A `scope` (can be `compile`, `runtime`, `provided` or `test`)
* The reference to a `bom` or a `repository` that must be added to the project once that dependency is added
* A `versionRange` used to determine the Spring Boot versions that are compatible with the dependency
* A mandatory identifier. If no further information is provided, a Spring Boot starer
with that id is assumed.
* A `name` and `description` used in the generated meta-data and the web ui.
* A `groupId` and `artifactId` to define the coordinates of the dependency.
* A `version` if Spring Boot does not already provide a dependency management for
that dependency.
* A `scope` (can be `compile`, `runtime`, `provided` or `test`).
* The reference to a `bom` or a `repository` that must be added to the project once
that dependency is added.
* A `versionRange` used to determine the Spring Boot versions that are compatible
with the dependency.
* Links to resources such as a guide or a reference doc section.
TIP: Check {code}/src/main/groovy/io/spring/initializr/metadata/Dependency.groovy[the code] for a full list of the available configuration options.
TIP: Check {sc-initializr-generator}/metadata/Dependency.groovy[the code] for a full
list of the available configuration options.
Here is the most basic dependency entry you could have
@ -81,9 +116,14 @@ initializr:
TIP: The `security` dependency is held within a group called "Core".
This adds an option name `Security` with a tooltip showing the description above. If a project is generated with that dependency, the `org.springframework.boot:spring-boot-starter-security` dependency will be added to the project.
This adds an option name `Security` with a tooltip showing the description above. If
a project is generated with that dependency, the
`org.springframework.boot:spring-boot-starter-security` dependency will be added to
the project.
Let's now add a custom dependency that is not managed by Spring Boot and that only work from Spring Boot `1.2.0.RELEASE` and onwards but should not be used in the 1.3 lines and further for some reason.
Let's now add a custom dependency that is not managed by Spring Boot and that only
work from Spring Boot `1.2.0.RELEASE` and onwards but should not be used in the 1.3
lines and further for some reason.
```yml
initializr:
@ -100,19 +140,34 @@ initializr:
versionRange: "[1.2.0.RELEASE,1.3.0.M1)"
```
If one selects this entry, the `com.example.foo:foo-core}` dependency will be added and the Bill of Materials and repository for `foo` will be added automatically to the project as well (see the "Env section" above for a reference to those identifiers). Because the bom provides a dependency management for `foo-core` there is no need to hardcode the version in the configuration.
If one selects this entry, the `com.example.foo:foo-core}` dependency will be added
and the Bill of Materials and repository for `foo` will be added automatically to
the project as well (see the "Env section" above for a reference to those
identifiers). Because the bom provides a dependency management for `foo-core` there
is no need to hard code the version in the configuration.
The `versionRange` syntax follows some simple rules: a square bracket "[" or "]" denotes an inclusive end of the range and a round bracket "(" or ")" denotes an exclusive end of the range. A range can also be unbounded by defining a a single version. In the example above, the dependency will be available as from `1.2.0.RELEASE` up to, not included, `1.3.0.M1` (which is the first milestone of the 1.3 line).
The `versionRange` syntax follows some simple rules: a square bracket "[" or "]"
denotes an inclusive end of the range and a round bracket "(" or ")" denotes an
exclusive end of the range. A range can also be unbounded by defining a a single
version. In the example above, the dependency will be available as from
`1.2.0.RELEASE` up to, not included, `1.3.0.M1` (which is the first milestone of the
1.3 line).
### Dependency group
A dependency group gather a set of dependencies as well as some common settings: `bom`, `repository` and `versionRange`. If one of them is set, it is applied for all dependencies within that group. It is still possible to override a particular value at the dependency level.
A dependency group gather a set of dependencies as well as some common settings:
`bom`, `repository` and `versionRange`. If one of them is set, it is applied for all
dependencies within that group. It is still possible to override a particular value
at the dependency level.
## Other sections
The other section defines the default and the list of available options in the web UI. This also drives how the meta-data for your instance are generated and tooling support is meant to react to that.
The other section defines the default and the list of available options in the web
UI. This also drives how the meta-data for your instance are generated and tooling
support is meant to react to that.
For instance, if you want your groupId to default to `org.acme` and the `javaVersions` to only be `1.7` and `1.8` you would write the following config:
For instance, if you want your groupId to default to `org.acme` and the
`javaVersions` to only be `1.7` and `1.8` you would write the following config:
```yml
initializr:
@ -124,4 +179,3 @@ initializr:
- id: 1.7
default: false
```

View File

@ -0,0 +1,43 @@
[[boot-documentation]]
= Spring Initializr Documentation
Spring Initializr provides an extensible API to generate quickstart projects. It also
provides a configurable service: you can see our default instance at
https://start.spring.io. It provides a simple web UI to configure the project to
generate and endpoints that you can use via plain HTTP.
Spring Initializr also exposes an endpoint that serves its metadata in a
<<metadata-format.adoc#metadata-format,well-known format>> to allow third-party
clients to provide the necessary assistance.
Finally, Initializr offers a <<configuration-format.adoc#configuration-format,
configuration structure>> to define all the aspects related to the project to
generate: list of dependencies, supported java and boot versions, etc.
[[initializr-documentation-about]]
== About the documentation
The Spring Initializr reference guide is available as
{spring-initializr-docs}/html[html],
{spring-initializr-docs}/pdf/spring-boot-reference.pdf[pdf]
and {spring-initializr-docs}/epub/spring-boot-reference.epub[epub] documents. The
latest copy is available at {spring-initializr-docs-current}.
Copies of this document may be made for your own use and for
distribution to others, provided that you do not charge any fee for such copies and
further provided that each copy contains this Copyright Notice, whether distributed
in print or electronically.
[[initializr-documentation-getting-help]]
== Getting help
Having trouble with Spring Initializr, We'd like to help!
* Ask a question on https://gitter.im/spring-io/initializr[Gitter].
* Report bugs with Spring Initializr at https://github.com/spring-io/initializr/issues.
NOTE: All of Spring Initializr is open source, including the documentation! If you
find problems with the docs; or if you just want to improve them, please
{github-code}[get involved].

View File

@ -1,36 +0,0 @@
# Third Party Starters
Spring Initializr (start.spring.io) provides an opinionated, web based generator for Spring Boot-based projects. start.spring.io provides a number of core starters as well as 3rd party contributed starters. While its possible to create 3rd party starter POMs without having them listed on start.spring.io, members of the community have asked for guidelines to be considered for inclusion in our production instance.
These guidelines aim to balance:
. An opinionated getting started experience
. Alignment with the overall direction of the Spring ecosystem
. Community contributions
. Community confidence in the long term viability and support for 3rd party starters
## Guidelines
. Code of Conduct
* Anyone contributing to any of the projects in the Spring portfolio, including Spring Initializr, must adhere to our Code of Conduct
. Open sourced and available on Maven central
* The library must be open sourced and available in Maven Central repository. Please see the Maven Central requirements for more details
* The project must be made available with an appropriate OSS license which is deemed compatible with the Apache 2.0 license
. Community
* There should be a sizeable community that are actively using and maintaining the library
* An established support forum such as Stack Overflow and issue tracker
. Spring Boot Compliance:
* The starter should comply with http://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-custom-starter-naming[the rules of a 3rd party starter].
* If the starter provides configuration entries, they should have proper meta-data (including documentation)
* start.spring.io will host one starter POM per 3rd party library
* The starter should be actively maintained and upgraded to the newest version of Spring Boot if necessary
. Dependencies:
* The 3rd party starter POM should not bring in any supporting dependencies that arent compatible with the Apache 2.0 license
* All of these supporting dependencies must be available in Maven Central
* Dependencies should be compatible with Spring Boots core starters
. Test Coverage:
* The 3rd party starter should have proper test coverage to validate that it works properly with Spring Boot
Testing should encompass combinations of optional dependencies using standalone sample projects
. Spring Engineering Review:
* The Spring Boot team periodically reviews starter statistics and may decide to remove 3rd party starters from start.spring.io if they are not being used. The main driver is to help keep Spring Boot opinionated and remove choices that arent being used by large audiences.
* Even if these requirements are met, the Spring Boot team may decide that a proposed 3rd party starter does not meet the strategic direction of Spring Boot and the overall portfolio. In this case, its still possible to create and share a 3rd party starters but they wont be listed on start.spring.io.

View File

@ -7,17 +7,25 @@ Stéphane Nicoll; Dave Syer
:numbered:
:icons: font
:hide-uri-scheme:
:test-examples: ../../test/java/io/spring/initializr
:github-tag: master
:github-repo: spring-io/initializr
:github-raw: https://raw.github.com/{github-repo}/{github-tag}
:github-code: https://github.com/{github-repo}/tree/{github-tag}
:github-wiki: https://github.com/{github-repo}/wiki
:github-master-code: https://github.com/{github-repo}/tree/master
:sc-initializr-generator: {github-code}/initializr-generator/src/main/groovy/io/spring/initializr
:sc-initializr-service: {github-code}/initializr-service/src/main
:spring-initializr-docs-version: current
:spring-initializr-docs: http://docs.spring.io/initializr/docs/{spring-initializr-docs-version}/reference
:spring-initializr-docs-current: http://docs.spring.io/initializr/docs/current/reference
// ======================================================================================
include::documentation-overview.adoc[leveloffset=+1]
include::metadata-format.adoc[leveloffset=+1]
include::using-the-stubs.adoc[leveloffset=+1]
include::configuration-format.adoc[leveloffset=+1]
include::guidelines-for-3rd-party-starters.adoc[leveloffset=+1]
// ======================================================================================

View File

@ -1,54 +1,79 @@
[[metadata-format]]
= Metadata Format
This section describes the hal/json structure of the metadata exposed by the
initializr. Such metadata can be used by third party clients to provide a list of
options and default settings that can be used to request the creation of a project.
Each third-party client is advised to set a `User-Agent` header for *each* request
sent to the service. A good structure for a user agent is `clientId/clientVersion`
(i.e. `foo/1.2.0` for the "foo" client and version `1.2.0`).
This section describes the hal/json structure of the metadata exposed by the initializr. Such metadata can be used by third party clients to provide a list of options and default settings that can be used to request the creation of a project.
Each third-party client is advised to set a `User-Agent` header for *each* request sent to the service. A good structure for a user agent is `clientId/clientVersion` (i.e. `foo/1.2.0` for the "foo" client and version `1.2.0`).
== Content
Any third party client can retrieve the capabilities of the service by issuing a
`GET` on the root URL using the following `Accept` header:
`application/vnd.initializr.v2.1+json`. Please note that the metadata may evolve in a
non backward compatible way in the future so adding this header ensures the service
returns the metadata format you expect.
Any third party client can retrieve the capabilities of the service by issuing a `GET` on the root URL using the following `Accept` header: `application/vnd.initializr.v2+json`. Please note that the metadata may evolve in a non backward compatible way in the future so adding this header ensures the service returns the metadata format you expect.
This is a full example of an output for a service running at `https://start.spring.io`:
This is an example output for a service running at `https://start.spring.io`:
.request
include::{snippets}/metadataWithV2AcceptHeader/http-request.adoc[]
include::{snippets}/metadataWithCurrentAcceptHeader/http-request.adoc[]
.response
include::{snippets}/metadataWithV2AcceptHeader/http-response.adoc[]
include::{snippets}/metadataWithCurrentAcceptHeader/http-response.adoc[]
The current capabilities are the following:
* Project dependencies: these are the _starters_ really or actually any dependency that we might want to add to the project.
* Project types: these define the action that can be invoked on this service and a description of what it would produce (for instance a zip holding a pre-configured Maven project). Each type may have one more tags that further define what it generates
* Packaging: the kind of projects to generate. This merely gives a hint to the component responsible to generate the project (for instance, generate an executable _jar_ project)
* Project dependencies: these are the _starters_ really or actually any dependency
that we might want to add to the project.
* Project types: these define the action that can be invoked on this service and a
description of what it would produce (for instance a zip holding a pre-configured
Maven project). Each type may have one more tags that further define what it
generates.
* Packaging: the kind of projects to generate. This merely gives a hint to the
component responsible to generate the project (for instance, generate an executable
_jar_ project).
* Java version: the supported java versions
* Language: the language to use (e.g. Java)
* Boot version: the Spring Boot version to use
* Additional basic information such as: `groupId`, `artifactId`, `version`, `name`, `description` and `packageName`
* Additional basic information such as: `groupId`, `artifactId`, `version`, `name`,
`description` and `packageName`.
Each top-level attribute (i.e. capability) has a standard format:
* A `type` attribute that defines the semantic of the attribute (see below)
* A `default` attribute that defines either the default value or the reference to the default value
* A `values` attribute that defines the set of acceptable values (if any). This can be hierarchical (with `values` being held in `values`). Each item in a `values` array can have an `id`, `name` and `description`)
* A `type` attribute that defines the semantic of the attribute (see below).
* A `default` attribute that defines either the default value or the reference to
the default value.
* A `values` attribute that defines the set of acceptable values (if any). This can
be hierarchical (with `values` being held in `values`). Each item in a `values` array
can have an `id`, `name` and `description`).
The following attribute `type` are supported:
* `text`: defines a simple text value with no option
* `single-select`: defines a simple value to be chosen amongst the specified options
* `hierarchical-multi-select`: defines a hierarchical set of values (values in values) with the ability to select multiple values
* `action`: a special type that defines the attribute defining the action to use
* `text`: defines a simple text value with no option.
* `single-select`: defines a simple value to be chosen amongst the specified options.
* `hierarchical-multi-select`: defines a hierarchical set of values (values in
values) with the ability to select multiple values.
* `action`: a special type that defines the attribute defining the action to use.
Each action is defined as a HAL-compliant URL. For instance, the `maven-project` type templated URL is defined as follows:
Each action is defined as a HAL-compliant URL. For instance, the `maven-project` type
templated URL is defined as follows:
._links.maven-project
include::{snippets}/metadataWithV2AcceptHeader/response-fields/_links.maven-project.adoc[]
.Type link example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/_links.maven-project.adoc[]
You can use Spring HATEOAS and the `UriTemplate` helper in particular to generate an URI from template variables. Note that the variables match the name of top-level attribute in the metadata document. If you can't parse such URI, the `action` attribute of each type gives you the root action to invoke on the server. This requires more manual handling on your end.
You can use Spring HATEOAS and the `UriTemplate` helper in particular to generate an
URI from template variables. Note that the variables match the name of top-level
attribute in the metadata document. If you can't parse such URI, the `action`
attribute of each type gives you the root action to invoke on the server. This
requires more manual handling on your end.
=== Project dependencies
A dependency is usually the coordinates of a _starter_ module but it can be just as well be a regular dependency. A typical dependency structure looks like this:
A dependency is usually the coordinates of a _starter_ module but it can be just as
well be a regular dependency. A typical dependency structure looks like this:
```json
{
@ -58,58 +83,92 @@ A dependency is usually the coordinates of a _starter_ module but it can be just
}
```
The name is used as a display name to be shown in whatever UI used by the remote client. The id can be anything, really as the actual dependency definition is defined through configuration. If no id is defined, a default one is built using the `groupId` and `artifactId` of the dependency. Note in particular that the version is **never** used as part of an automatic id.
The name is used as a display name to be shown in whatever UI used by the remote
client. The id can be anything, really as the actual dependency definition is
defined through configuration. If no id is defined, a default one is built using the
`groupId` and `artifactId` of the dependency. Note in particular that the version is
**never** used as part of an automatic id.
Each dependency belongs to a group. The idea of the group is to gather similar
dependencies and order them. Here is a value containing the `core` group to
illustrates the feature:
.Dependency group example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/dependencies.values.0.adoc[]
Each dependency can have _links_ (in a HAL-compliant format). Links are grouped by
"relations" that provide a semantic to the link. A link can also have a _title_ and
its URI can be templated. At the moment, the only valid parameter is `bootVersion`.
The official relations are:
* `guide`: link to an how-to or guide that explain how to get started
* `reference`: link to a section of a reference guide (documentation)
Each dependency belongs to a group. The idea of the group is to gather similar dependencies and order them. Here is a value containing the `core` group to illustrates the feature:
.dependencies.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/dependencies.values.0.adoc[]
=== Project types
The `type` element defines what kind of project can be generated and how. For
instance, if the service exposes the capability to generate a Maven project, this
would look like this:
The `type` element defines what kind of project can be generated and how. For instance, if the service exposes the capability to generate a Maven project, this would look like this:
.Project type example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/type.values.0.adoc[]
.type.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/type.values.0.adoc[]
You should not rely on the output format depending that information. Always use the
response headers that define a `Content-Type` and also a `Content-Disposition`
header.
You should not rely on the output format depending that information. Always use the response headers that define a `Content-Type` and also a `Content-Disposition` header.
Note that each id has a related HAL-compliant link that can be used to generate a
proper URI based on template variables. The top-level `type` has, as any other
attribute, a `default` attribute that is a hint to select what the service consider
to be a good default.
Note that each id has a related HAL-compliant link that can be used to generate a proper URI based on template variables. The top-level `type` has, as any other attribute, a `default` attribute that is a hint to select what the service consider to be a good default.
The `action` attribute defines the endpoint the client should contact to actually
generate a project of that type if you can't use the HAL-compliant url.
The `tags` object is used to categorize the project type and give _hints_ to 3rd
party client. For instance, the _build_ tag defines the build system the project is
going to use and the _format_ tag defines the format of the generated content (i.e.
here a complete project vs. a build file. Note that the `Content-type` header of the
reply provides additional metadata).
The `action` attribute defines the endpoint the client should contact to actually generate a project of that type if you can't use the HAL-compliant url.
The `tags` object is used to categorize the project type and give _hints_ to 3rd party client. For instance, the _build_ tag defines the build system the project is going to use and the _format_ tag defines the format of the generated content (i.e. here a complete project vs. a build file. Note that the `Content-type` header of the reply provides additional metadata).
=== Packaging
The `packaging` element defines the kind of project that should be generated.
The `packaging` element defines the kind of project that should be generated.
.packaging.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/packaging.values.0.adoc[]
.Packaging example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/packaging.values.0.adoc[]
The obvious values for this element are `jar` and `war`.
=== Java version
=== Java version
The `javaVersion` element provides a list of possible java versions for the project:
.javaVersion.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/javaVersion.values.0.adoc[]
.Java example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/javaVersion.values.0.adoc[]
=== Languages
The `language` element provides a list of possible languages for the project:
.language.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/language.values.0.adoc[]
.Language example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/language.values.0.adoc[]
=== Boot version
The `bootVersion` element provides the list of available boot versions
.bootVersion.values[0]
include::{snippets}/metadataWithV2AcceptHeader/response-fields/bootVersion.values.0.adoc[]
.Spring Boot version example
include::{snippets}/metadataWithCurrentAcceptHeader/response-fields/bootVersion.values.0.adoc[]
== Defaults
Each top-level element has a `default` attribute that should be used as a hint to provide the default value in the relevant UI component.
Each top-level element has a `default` attribute that should be used as a hint to
provide the default value in the relevant UI component.

View File

@ -1,48 +1,43 @@
:project-version: 1.0.0.BUILD-SNAPSHOT
= Using the Stubs
The Initializr project publishes
https://github.com/tomakehurst/wiremock[WireMock] stubs for all the
JSON responses that are tested in the project. If you are writing a
client for the Initializr service, you can use these stubs to test
your own code. You can consume them with the raw Wiremock APIs, or via
some features of
https://github.com/spring-cloud/spring-cloud-contract[Spring Cloud
Contract].
https://github.com/tomakehurst/wiremock[WireMock] stubs for all the JSON responses
that are tested in the project. If you are writing a client for the Initializr
service, you can use these stubs to test your own code. You can consume them with the
raw Wiremock APIs, or via some features of
https://github.com/spring-cloud/spring-cloud-contract[Spring Cloud Contract].
WireMock is an embedded web server that analyses incoming requests and chooses stub
responses based on matching some rules (e.g. a specific header value). So if you send
it a request which matches one of its stubs, it will send you a response as if it was
a real Initializr service, and you can use that to do full stack integration testing
of your client.
WireMock is an embedded web server that analyses incoming requests and
chooses stub responses based on matching some rules (e.g. a specific
header value). So if you send it a request which matches one of its
stubs, it will send you a response as if it was a real Initializr
service, and you can use that to do full stack integration testing of
your client.
== Using WireMock with Spring Boot
A convenient way to consume the stubs in your project is to add a test
dependency:
A convenient way to consume the stubs in your project is to add a test dependency:
[source,xml,indent=0,subs="attributes,specialchars"]
----
<dependency>
<groupId>io.spring.initializr</groupId>
<artifactId>initializr</artifactId>
<artifactId>initializr-web</artifactId>
<classifier>stubs</classifier>
<version>{project-version}</version>
<scope>test</scope>
</dependency>
----
and then pull the stubs from the classpath. In a Spring Boot
application, using Spring Cloud Contract, you can start a WireMock
server and register all the stubs with it like this:
and then pull the stubs from the classpath. In a Spring Boot application, using
Spring Cloud Contract, you can start a WireMock server and register all the stubs
with it like this:
[source,java,subs="attributes"]
----
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureWireMock(port = 0, stubs="classpath:META-INF/io.spring.initializr/initializr/{project-version}")
@AutoConfigureWireMock(port = 0,
stubs="classpath:META-INF/io.spring.initializr/initializr-web/{spring-initializr-version}")
public class ClientApplicationTests {
@Value("${wiremock.server.port}")
@ -53,47 +48,44 @@ public class ClientApplicationTests {
}
----
Alternatively you can register individual stubs with the server by
autowiring it, and using its own API. For example:
Alternatively you can configure the stub runner to look for the artifact. The example
below will automatically download, if necessary, the latest version of the initializr
stubs:
[source,java,indent=0]
----
@Value("classpath:META-INF/io.spring.initializr/initializr/{project-version}/mappings/metadataWithV2AcceptHeader.json")
private Resource root;
@Autowired
private WireMockServer server;
@Test
public void testDependencies() throws IOException {
server.addStubMapping(StubMapping.buildFrom(StreamUtils.copyToString(
root.getInputStream(), Charset.forName("UTF-8"))));
...
}
include::{test-examples}/stub/InitializrIntegrationTests.java[tag=test]
----
Then you have a server that returns the stub of the JSON metadata
("metadataWithV2AcceptHeader.json") when you send it a header "Accept:
application/vnd.initializr.v2+json" (as recommended).
[TIP]
====
If you want to test a specific version or validate your API against multiple versions
you can define the version to use in the annotation, something like
[source,java,indent=0,subs="attributes+"]
----
@AutoConfigureStubRunner(
ids = "io.spring.initializr:initializr-web:{spring-initializr-version}",
workOffline = true)
public class InitializrIntegrationTests {
...
}
----
====
Then you have a server that returns the stub of the JSON metadata
(`metadataWithCurrentAcceptHeader.json`) when you send it a header
`Accept:application/vnd.initializr.v2.1+json` (as recommended).
NOTE: Spring Cloud Contract also has support for easily running stubs
of multiple services on different ports. You might find that useful if
your client uses other services. To just load up the Initializr stubs
in your test case you use `@AutoConfigureStubRunner` (instead of
`@AutoConfigureWireMock`)
== Names and Paths of Stubs
The stubs are laid out in a jar file in a form (under "/mappings")
that can be consumed by WireMock just by setting its file source. The
names of the individual stubs are the same as the method names of the
test cases that generated them in the Initializr project. So for
example there is a test case "metadataWithV2AcceptHeader" in
`MainControllerIntegrationTests` that makes assertions about the
response when the accept header is
"application/vnd.initializr.v2+json". The response is recorded in the
stub, and it will match in WireMock if the same headers and request
parameters that were used in the Initializr test case and used in the
client. The method name usually summarizes what those values are.
The stubs are laid out in a jar file in a form (under "/mappings") that can be
consumed by WireMock just by setting its file source. The names of the individual
stubs are the same as the method names of the test cases that generated them in the
Initializr project. So for example there is a test case "metadataWithV2AcceptHeader"
in `MainControllerIntegrationTests` that makes assertions about the response when the
accept header is `application/vnd.initializr.v2.1+json`. The response is recorded in
the stub, and it will match in WireMock if the same headers and request parameters
that were used in the Initializr test case and used in the client. The method name
usually summarizes what those values are.

View File

@ -1,30 +1,31 @@
package io.spring.initializr.stub;
import java.io.IOException;
import java.util.Collections;
import java.net.URI;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.cloud.contract.stubrunner.StubFinder;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.web.client.RestTemplate;
import static org.assertj.core.api.Assertions.*;
import static org.springframework.boot.test.context.SpringBootTest.*;
/**
*
* @author Stephane Nicoll
*/
// tag::test[]
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.NONE)
// Need a spring boot app. Doesn't really have one
@AutoConfigureStubRunner(
ids = "io.spring.initializr:initializr-web",
workOffline = true)
@ -33,22 +34,36 @@ public class InitializrIntegrationTests {
@Autowired
private StubFinder stubFinder;
@Autowired
private RestTemplateBuilder restTemplateBuilder;
private RestTemplate restTemplate;
@Test
public void contextLoads() throws IOException {
String url = stubFinder.findStubUrl("io.spring.initializr:initializr-web").toString();
RestTemplate template = restTemplateBuilder
.interceptors((request, body, execution) -> {
request.getHeaders().setAccept(Collections.singletonList(
MediaType.valueOf("application/vnd.initializr.v2+json")));
return execution.execute(request, body);
}).build();
// Can we write an assert that makes more sense in the context of the doc?
assertThat(template.getForEntity(url + "/", String.class)
.getBody()).contains("dependencies");
public void testCurrentMetadata() throws IOException {
RequestEntity<Void> request = RequestEntity.get(createUri("/"))
.accept(MediaType.valueOf("application/vnd.initializr.v2.1+json"))
.build();
ResponseEntity<String> response = this.restTemplate
.exchange(request, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
// other assertions here
}
private URI createUri(String path) {
String url = this.stubFinder.findStubUrl(
"io.spring.initializr:initializr-web").toString();
return URI.create(url + path);
}
@TestConfiguration
static class Config {
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
}
}
// end::test[]

View File

@ -6,6 +6,7 @@ import io.spring.initializr.web.autoconfigure.InitializrAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* A sample app where the Initializr auto-configuration has been disabled.
*
* @author Stephane Nicoll
*/

View File

@ -116,7 +116,7 @@
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>stub</id>
<id>build-assets</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
@ -125,6 +125,7 @@
<configuration>
<attach>true</attach>
<descriptors>
<descriptor>${basedir}/src/assembly/snippets.xml</descriptor>
<descriptor>${basedir}/src/assembly/stub.xml</descriptor>
</descriptors>
</configuration>

View File

@ -0,0 +1,19 @@
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>snippets</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target/snippets</directory>
<outputDirectory/>
<excludes>
<exclude>stubs/**</exclude>
</excludes>
</fileSet>
</fileSets>
</assembly>

View File

@ -168,15 +168,15 @@ class MainControllerIntegrationTests extends AbstractInitializrControllerIntegra
@Test
void metadataWithV2AcceptHeader() {
requests.setFields("_links.maven-project", "dependencies.values[0]", "type.values[0]",
"javaVersion.values[0]", "packaging.values[0]",
"bootVersion.values[0]", "language.values[0]");
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2+json')
validateMetadata(response, InitializrMetadataVersion.V2.mediaType, '2.0.0', JSONCompareMode.STRICT)
}
@Test
void metadataWithCurrentAcceptHeader() {
requests.setFields("_links.maven-project", "dependencies.values[0]", "type.values[0]",
"javaVersion.values[0]", "packaging.values[0]",
"bootVersion.values[0]", "language.values[0]");
ResponseEntity<String> response = invokeHome(null, 'application/vnd.initializr.v2.1+json')
assertThat(response.getHeaders().getFirst(HttpHeaders.ETAG), not(nullValue()))
validateContentType(response, AbstractInitializrControllerIntegrationTests.CURRENT_METADATA_MEDIA_TYPE)

15
pom.xml
View File

@ -128,6 +128,16 @@
</plugins>
<pluginManagement>
<plugins>
<plugin>
<groupId>com.agilejava.docbkx</groupId>
<artifactId>docbkx-maven-plugin</artifactId>
<version>2.0.15</version>
</plugin>
<plugin>
<groupId>org.asciidoctor</groupId>
<artifactId>asciidoctor-maven-plugin</artifactId>
<version>1.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
@ -152,6 +162,11 @@
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.10</version>
</plugin>
<plugin>
<groupId>org.codehaus.gmavenplus</groupId>
<artifactId>gmavenplus-plugin</artifactId>