source: uri/docs/source/user/building.rst@ 230

Last change on this file since 230 was 230, checked in by wouter, 4 years ago

#91 clone https://pypi.org/project/rfc3986/

File size: 5.6 KB
RevLine 
[230]1===============
2 Building URIs
3===============
4
5Constructing URLs often seems simple. There are some problems with
6concatenating strings to build a URL:
7
8- Certain parts of the URL disallow certain characters
9
10- Formatting some parts of the URL is tricky and doing it manually isn't fun
11
12To make the experience better |rfc3986| provides the
13:class:`~rfc3986.builder.URIBuilder` class to generate valid
14:class:`~rfc3986.uri.URIReference` instances. The
15:class:`~rfc3986.builder.URIBuilder` class will handle ensuring that each
16component is normalized and safe for real world use.
17
18
19Example Usage
20=============
21
22.. note::
23
24 All of the methods on a :class:`~rfc3986.builder.URIBuilder` are
25 chainable (except :meth:`~rfc3986.builder.URIBuilder.finalize` and
26 :meth:`~rfc3986.builder.URIBuilder.geturl` as neither returns a
27 :class:`~rfc3986.builder.URIBuilder`).
28
29Building From Scratch
30---------------------
31
32Let's build a basic URL with just a scheme and host. First we create an
33instance of :class:`~rfc3986.builder.URIBuilder`. Then we call
34:meth:`~rfc3986.builder.URIBuilder.add_scheme` and
35:meth:`~rfc3986.builder.URIBuilder.add_host` with the scheme and host
36we want to include in the URL. Then we convert our builder object into
37a :class:`~rfc3986.uri.URIReference` and call
38:meth:`~rfc3986.uri.URIReference.unsplit`.
39
40.. doctest::
41
42 >>> from rfc3986 import builder
43 >>> print(builder.URIBuilder().add_scheme(
44 ... 'https'
45 ... ).add_host(
46 ... 'github.com'
47 ... ).finalize().unsplit())
48 https://github.com
49
50
51Replacing Components of a URI
52-----------------------------
53
54It is possible to update an existing URI by constructing a builder from an
55instance of :class:`~rfc3986.uri.URIReference` or a textual representation:
56
57.. doctest::
58
59 >>> from rfc3986 import builder
60 >>> print(builder.URIBuilder.from_uri("http://github.com").add_scheme(
61 ... 'https'
62 ... ).finalize().unsplit())
63 https://github.com
64
65The Builder is Immutable
66------------------------
67
68Each time you invoke a method, you get a new instance of a
69:class:`~rfc3986.builder.URIBuilder` class so you can build several different
70URLs from one base instance.
71
72.. doctest::
73
74 >>> from rfc3986 import builder
75 >>> github_builder = builder.URIBuilder().add_scheme(
76 ... 'https'
77 ... ).add_host(
78 ... 'api.github.com'
79 ... )
80 >>> print(github_builder.add_path(
81 ... '/users/sigmavirus24'
82 ... ).finalize().unsplit())
83 https://api.github.com/users/sigmavirus24
84 >>> print(github_builder.add_path(
85 ... '/repos/sigmavirus24/rfc3986'
86 ... ).finalize().unsplit())
87 https://api.github.com/repos/sigmavirus24/rfc3986
88
89Convenient Path Management
90--------------------------
91
92Because our builder is immutable, one could use the
93:class:`~rfc3986.builder.URIBuilder` class to build a class to make HTTP
94Requests that used the provided path to extend the original one.
95
96.. doctest::
97
98 >>> from rfc3986 import builder
99 >>> github_builder = builder.URIBuilder().add_scheme(
100 ... 'https'
101 ... ).add_host(
102 ... 'api.github.com'
103 ... ).add_path(
104 ... '/users'
105 ... )
106 >>> print(github_builder.extend_path("sigmavirus24").geturl())
107 https://api.github.com/users/sigmavirus24
108 >>> print(github_builder.extend_path("lukasa").geturl())
109 https://api.github.com/users/lukasa
110
111
112Convenient Credential Handling
113------------------------------
114
115|rfc3986| makes adding authentication credentials convenient. It takes care of
116making the credentials URL safe. There are some characters someone might want
117to include in a URL that are not safe for the authority component of a URL.
118
119.. doctest::
120
121 >>> from rfc3986 import builder
122 >>> print(builder.URIBuilder().add_scheme(
123 ... 'https'
124 ... ).add_host(
125 ... 'api.github.com'
126 ... ).add_credentials(
127 ... username='us3r',
128 ... password='p@ssw0rd',
129 ... ).finalize().unsplit())
130 https://us3r:p%40ssw0rd@api.github.com
131
132Managing Query String Parameters
133--------------------------------
134
135Further, |rfc3986| attempts to simplify the process of adding query parameters
136to a URL. For example, if we were using Elasticsearch, we might do something
137like:
138
139.. doctest::
140
141 >>> from rfc3986 import builder
142 >>> print(builder.URIBuilder().add_scheme(
143 ... 'https'
144 ... ).add_host(
145 ... 'search.example.com'
146 ... ).add_path(
147 ... '_search'
148 ... ).add_query_from(
149 ... [('q', 'repo:sigmavirus24/rfc3986'), ('sort', 'created_at:asc')]
150 ... ).finalize().unsplit())
151 https://search.example.com/_search?q=repo%3Asigmavirus24%2Frfc3986&sort=created_at%3Aasc
152
153If one also had an existing URL with query string that we merely wanted to
154append to, we can also do that with |rfc3986|.
155
156.. doctest::
157
158 >>> from rfc3986 import builder
159 >>> print(builder.URIBuilder().from_uri(
160 ... 'https://search.example.com/_search?q=repo%3Asigmavirus24%2Frfc3986'
161 ... ).extend_query_with(
162 ... [('sort', 'created_at:asc')]
163 ... ).finalize().unsplit())
164 https://search.example.com/_search?q=repo%3Asigmavirus24%2Frfc3986&sort=created_at%3Aasc
165
166Adding Fragments
167----------------
168
169Finally, we provide a way to add a fragment to a URL. Let's build up a URL to
170view the section of the RFC that refers to fragments:
171
172.. doctest::
173
174 >>> from rfc3986 import builder
175 >>> print(builder.URIBuilder().add_scheme(
176 ... 'https'
177 ... ).add_host(
178 ... 'tools.ietf.org'
179 ... ).add_path(
180 ... '/html/rfc3986'
181 ... ).add_fragment(
182 ... 'section-3.5'
183 ... ).finalize().unsplit())
184 https://tools.ietf.org/html/rfc3986#section-3.5
Note: See TracBrowser for help on using the repository browser.